web-dev-qa-db-fra.com

SQL: Comment trouver des doublons basés sur deux champs?

J'ai des lignes dans une table de base de données Oracle qui devraient être uniques pour une combinaison de deux champs, mais la contrainte unique n'est pas définie sur la table. Je dois donc rechercher toutes les lignes qui ne respectent pas la contrainte moi-même à l'aide de SQL. Malheureusement, mes maigres compétences en SQL ne sont pas à la hauteur.

Ma table a trois colonnes qui sont pertinentes: id_entité, id_station et obs_year. Pour chaque ligne, la combinaison station_id et obs_year devrait être unique, et je veux savoir s'il existe des lignes qui ne respectent pas cette règle en les effaçant avec une requête SQL.

J'ai essayé le code SQL suivant (suggéré par cette question précédente ) mais cela ne fonctionne pas pour moi (la colonne ORA-00918 est définie de manière ambiguë):

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

Est-ce que quelqu'un peut suggérer ce que je fais mal et/ou comment résoudre ce problème?

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
37
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)
11
Michael Pakhantsov

Réécrire votre requête

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

Je pense que l'erreur de colonne ambiguë (ORA-00918) était due au fait que vous étiez des colonnes selecting dont les noms apparaissaient à la fois dans le tableau et dans la sous-requête, mais vous n'avez pas spécifié si vous le vouliez à partir de dupes ou de mytable (appelé aussi t1.

Changez les 3 champs de la sélection initiale pour être

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

Vous devez spécifier la table pour les colonnes dans la sélection principale. De plus, en supposant que entity_id est la clé unique de mytable et qu'il est inutile de rechercher des doublons, vous ne devez pas y grouper des éléments dans la sous-requête dupes.

Essayer:

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

Ne pourriez-vous pas créer une nouvelle table contenant la contrainte unique, puis copier les données ligne par ligne en ignorant les échecs?

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

par Quassnoi est le plus efficace pour les grandes tables. J'ai eu cette analyse de coût:

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)
       ;

a donné un coût de 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
;

a donné un coût de 1271699

tandis que 

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
;

a donné un coût de 1021984

La table n'a pas été indexée ....

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

Spécifiez les champs pour rechercher les doublons sur SELECT et GROUP BY.

Cela fonctionne en utilisant GROUP BY pour trouver toutes les lignes qui correspondent à toutes les lignes basées sur les colonnes spécifiées. Le HAVING COUNT(*) > 1 indique que nous ne souhaitons voir que les lignes apparaissant plus d'une fois (et donc des doublons) 

0
grokster