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?
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
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)
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 select
ing 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
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
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?
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 ....
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)