2010-08-17 191 views
17

我在Oracle數據庫表中有行,對於兩個字段的組合應該是唯一的,但是在表上沒有設置唯一約束,所以我需要查找所有使用SQL自行違反約束的行。不幸的是,我微薄的SQL技能不能勝任。SQL:如何根據兩個字段查找重複項?

我的表格有三個相關的列:entity_id,station_id和obs_year。對於每一行,station_id和obs_year的組合應該是唯一的,並且我想通過用SQL查詢來清除它們是否存在違反這些行的行。

我曾嘗試以下SQL(由this previous question建議),但它不爲我工作(我得到含糊不清的ORA-00918列):

SELECT 
entity_id, station_id, obs_year 
FROM 
mytable t1 
INNER JOIN (
SELECT entity_id, station_id, obs_year FROM mytable 
GROUP BY entity_id, station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 

可有人建議我做錯了什麼,和/或如何解決這個問題?您查詢的

回答

33
SELECT * 
FROM (
     SELECT t.*, ROW_NUMBER() OVER (PARTITION BY station_id, obs_year ORDER BY entity_id) AS rn 
     FROM mytable t 
     ) 
WHERE rn > 1 
+0

非常感謝這個迴應。不幸的是,當我運行這個時,我得到一個「ORA-00923:FROM關鍵字找不到預期的地方」的消息。 – 2010-08-17 17:00:39

+0

@James:現在試試 – Quassnoi 2010-08-17 17:11:15

+0

在mssql中,必須在FROM()參數後面放置一個'as x'(名字並不重要)才能使其工作。很好的答案! – Mafii 2017-04-06 09:30:06

2

重新寫

SELECT 
t1.entity_id, t1.station_id, t1.obs_year 
FROM 
mytable t1 
INNER JOIN (
SELECT entity_id, station_id, obs_year FROM mytable 
GROUP BY entity_id, station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 

我覺得不明確的列錯誤(ORA-00918),是因爲你的select荷蘭國際集團列的名字出現在表和子查詢都,但你沒有如果你想要dupesmytable(別名爲t1)。

1

您不可以創建一個包含唯一約束的新表,然後逐行復制數據行,忽略故障嗎?

+0

是的,這是一個好主意,謝謝! 順便說一句,我試圖找出如何在使用註釋在我的實體類我的表創建約束(我使用JPA/Hibernate的Java開發人員),請參閱http://stackoverflow.com/questions/3504477/ how-to-specify-that-a-combination-of-columns-should-be-a-unique-constraint-使用 – 2010-08-17 16:45:47

2

更改初始選擇的3場是

SELECT 
t1.entity_id, t1.station_id, t1.obs_year 
10
SELECT entity_id, station_id, obs_year 
FROM mytable t1 
WHERE EXISTS (SELECT 1 from mytable t2 Where 
     t1.station_id = t2.station_id 
     AND t1.obs_year = t2.obs_year 
     AND t1.RowId <> t2.RowId) 
+0

看起來我們不能在視圖上執行此操作: ORA-01445:無法從沒有鍵保存表的聯合視圖中選擇ROWID – Thyag 2016-11-17 21:02:17

1

你需要指定表主選擇列。此外,假設entity_id是mytable的唯一鍵,並且與查找重複項無關,您不應該在dupes子查詢中對其進行分組。

嘗試:

SELECT t1.entity_id, t1.station_id, t1.obs_year 
FROM mytable t1 
INNER JOIN (
SELECT station_id, obs_year FROM mytable 
GROUP BY station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 
+0

感謝Mark對於在分組子查詢中未使用entity_id的提示,併爲說明性的例子。 – 2010-08-18 14:16:38

0
SELECT * 
FROM (
     SELECT t.*, ROW_NUMBER() OVER (PARTITION BY station_id, obs_year ORDER BY entity_id) AS rn 
     FROM mytable t 
     ) 
WHERE rn > 1 

由Quassnoi是最高效的大表。 我有這個分析成本:

SELECT a.dist_code, a.book_date, a.book_no 
FROM trn_refil_book a 
WHERE EXISTS (SELECT 1 from trn_refil_book b Where 
     a.dist_code = b.dist_code and a.book_date = b.book_date and a.book_no = b.book_no 
     AND a.RowId <> b.RowId) 
     ; 

給了1322341

SELECT a.dist_code, a.book_date, a.book_no 
FROM trn_refil_book a 
INNER JOIN (
SELECT b.dist_code, b.book_date, b.book_no FROM trn_refil_book b 
GROUP BY b.dist_code, b.book_date, b.book_no HAVING COUNT(*) > 1) c 
ON 
a.dist_code = c.dist_code and a.book_date = c.book_date and a.book_no = c.book_no 
; 

成本給了1271699

SELECT dist_code, book_date, book_no 
FROM (
     SELECT t.dist_code, t.book_date, t.book_no, ROW_NUMBER() OVER (PARTITION BY t.book_date, t.book_no 
      ORDER BY t.dist_code) AS rn 
     FROM trn_refil_book t 
     ) p 
WHERE p.rn > 1 
; 

給了1021984成本費用

該表沒有索引....

+0

正確地格式化您的答案。 – SSP 2013-12-03 04:56:18

0
SELECT entity_id, station_id, obs_year 
    FROM mytable 
GROUP BY entity_id, station_id, obs_year 
HAVING COUNT(*) > 1 

指定字段找到關於SELECT和GROUP BY都重複。

它的工作原理是利用GROUP BY找到匹配基於指定列的其他行的任何行。 該HAVING COUNT(*) > 1說,我們只有興趣看到任何行發生超過1次(因此重複)

+0

Hiya,這可能很好地解決了這個問題......但是如果你能夠提供一些關於它是如何工作和爲什麼工作的一些解釋,那麼它會很好:)不要忘記 - 堆棧溢出中有一堆新手,他們可以從你的專業知識中學到一兩件事 - 對你來說顯而易見的事情對他們來說可能並非如此。 – 2014-08-07 23:34:17

+0

謝謝Taryn。它通過使用GROUP BY來查找任何基於指定的列匹配任何其他行的行。 HAVING COUNT(*)> 1表示我們只對看到任何發生超過1次的行感興趣(因此重複) – grokster 2014-08-27 20:34:57

+0

嗨,別告訴我(在評論中)。我知道SQL,我不是要求我......這種解釋是「你完整答案的一部分」......所以請編輯你的答案並將其添加到那裏。 :) – 2014-08-28 00:01:55

相關問題