2010-01-29 7 views
4

Est-il possible en SQL de supprimer (une seule) les entrées dupliquées des colonnes composées (ici: city, zip)? Donc, si j'ai ce SQL:Supprimer les entrées dupliquées via SQL?

INSERT INTO foo (id, city, zip) VALUES (1, 'New York', '00000') 
INSERT INTO foo (id, city, zip) VALUES (2, 'New York', '00000') 

Puis-je supprimer le premier plus tard avec une instruction SQL? Mon approche ne fonctionne pas pour que

DELETE FROM foo (id, city, zip) 
     WHERE id IN 
      (SELECT id FROM foo GROUP BY id HAVING (COUNT(zip) > 1)) 
+2

Enlever seulement un ou en laisser un seul? Cela compte dès que vous avez des dupes avec 3 éléments correspondants. – Lucero

+0

lévy seulement un. – codevour

Répondre

6

Adapté de this article. Ces deux solutions sont génériques et devraient fonctionner sur n'importe quelle implémentation SQL raisonnable.

Supprimer les doublons en place:

DELETE T1 
FROM foo T1, foo T2 
WHERE (T1.city = T2.city AND foo1.zip=foo2.zip) -- Duplicate rows 
    AND T1.id > T2.id;       -- Delete the one with higher id 

simple et devrait fonctionner correctement pour les petites tables ou des tables avec des petits doublons.

Copier des enregistrements distincts à une autre table:

CREATE TABLE foo_temp LIKE(foo); 
INSERT INTO foo_temp (SELECT distinct city, zip) FORM foo; 
TRUNCATE TABLE foo; 

Si vous êtes assez chanceux d'avoir une séquence comme identifiant, simplement:

INSERT INTO foo SELECT * FROM foo_temp; 
DROP TABLE foo_temp; 

Un peu plus compliqué, mais très efficace pour très grandes tables avec beaucoup de doublons. Pour ceux-ci, créer un index pour (ville, zip) améliorerait incroyablement les performances de la requête.

+1

"Work in progress" - Je dois me rappeler de le faire aussi à l'avenir lors de l'édition ...;) – Lucero

+0

Yup. Je lance l'idée générale, empêchant les autres de perdre leur temps à courir avec la même idée. –

1

Il n'est pas clair quel SQL est pris en charge dans votre cas, car les différents dialectes ont des caractéristiques différentes. Ce qui vient à l'esprit est d'utiliser un classement sur zip dans la requête interne au lieu de HAVING et ne comprennent que ceux qui ont un rang> 1.

+0

SQL98 serait le meilleur – codevour

2

Dans SQL Server 2005 et plus:

WITH q AS 
     (
     SELECT *, 
       ROW_NUMBER() OVER (PARTITION BY city, zip ORDER BY id) AS rn, 
       COUNT(*) OVER (PARTITION BY city, zip ORDER BY id) AS cnt 
     FROM mytable 
     ) 
DELETE 
FROM q 
WHERE rn = 1 
     AND cnt > 1 

pour supprimer la première ligne (ayant les doublons),

WITH q AS 
     (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY city, zip ORDER BY id) AS rn 
     FROM mytable 
     ) 
DELETE 
FROM q 
WHERE rn = 2 

pour supprimer le premier doublon,

WITH q AS 
     (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY city, zip ORDER BY id) AS rn 
     FROM mytable 
     ) 
DELETE 
FROM q 
WHERE rn > 1 

pour supprimer tous les doublons.

+0

+1 - ce que je voulais dire avec mon commentaire, mais je ne suis pas assez courant pour l'écrire. – Lucero

1
DELETE FROM 
    cities 
WHERE 
    id 
NOT IN 
(
    SELECT id FROM 
    (
     -- Get the maximum id of any zip/city combination 
      -- This will work with both duped and non-duped rows 
     SELECT 
      MAX(id), 
      city, 
      zip 
     FROM 
      cities 
     GROUP BY 
      city, 
      zip 
    ) ids_only 
) 
0

La réponse acceptée n'a pas fonctionné sur mon oracle db. Cela fait:

DELETE FROM 
    mytable A 
WHERE 
    A.rowid > 
    ANY (
    SELECT 
     B.rowid 
    FROM 
     mytable B 
    WHERE 
     A.col1 = B.col1 
    AND 
     A.col2 = B.col2 
     ); 

(fonctionne également pour toute colonne au lieu de rowid.)

here trouvé.

Questions connexes