web-dev-qa-db-ja.com

SQL:2つのフィールドに基づいて重複を見つける方法

Oracleデータベーステーブルには2つのフィールドの組み合わせに対して一意である行がありますが、テーブルに一意の制約が設定されていないため、SQLを使用して制約に違反するすべての行を見つける必要があります。残念ながら、私の貧弱なSQLスキルはタスクに応じていません。

私のテーブルには、entity_id、station_id、obs_yearの3つの関連する列があります。各行について、station_idとobs_yearの組み合わせは一意である必要があります。SQLクエリでフラッシュすることにより、これに違反する行があるかどうかを確認したいと思います。

私は次のSQLを試してみました( この前の質問 で提案されています)が、それはうまくいきません(曖昧に定義された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

誰かが私が間違っていること、および/またはこれを解決する方法を提案できますか?

20
James Adams
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
40
Quassnoi
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)
12

クエリの書き直し

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)は、名前がテーブルとサブクエリの両方に表示されるselecting列だったが、dupesまたはfrom mytable(エイリアスはt1)。

初期選択の3つのフィールドを変更して

SELECT
t1.entity_id, t1.station_id, t1.obs_year
2
Basic

メイン選択で列のテーブルを指定する必要があります。また、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
1
user359040

一意の制約を含む新しいテーブルを作成してから、エラーを無視して、データを行ごとにコピーできませんでしたか?

1
fredley
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

by 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
Suresh Nambiar
_  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
grokster

3列の主キー制約があり、重複を見つける必要があるため、ここでの解決策の多くは面倒で理解しにくいと思いました。ここにオプションがあります

SELECT id, name, value, COUNT(*) FROM db_name.table_name
GROUP BY id, name, value
HAVING COUNT(*) > 1
0
Ben Petersen