187 votes

Supprimer les lignes dupliquées d'une petite table

J'ai une table dans une base de données PostgreSQL 8.3.8, qui n'a pas de clés/contraintes, et qui a plusieurs lignes avec exactement les mêmes valeurs.

J'aimerais supprimer tous les doublons et ne conserver qu'une seule copie de chaque ligne.

Une colonne en particulier (appelée "clé") peut être utilisée pour identifier les doublons, c'est-à-dire qu'il ne doit y avoir qu'une seule entrée pour chaque "clé" distincte.

Comment faire ? (Idéalement, avec une seule commande SQL).
La vitesse n'est pas un problème dans ce cas (il n'y a que quelques lignes).

10voto

Pablo Santa Cruz Points 73944

J'utiliserais une table temporaire :

create table tab_temp as
select distinct f1, f2, f3, fn
  from tab;

Ensuite, supprimez tab et renommer tab_temp en tab .

9voto

ruslan Points 5754

J'ai dû créer ma propre version. La version écrite par @a_horse_with_no_name est beaucoup trop lente sur ma table (21M de lignes). Et @rapimo ne supprime tout simplement pas les dups.

Voici ce que j'utilise sur PostgreSQL 9.5

DELETE FROM your_table
WHERE ctid IN (
  SELECT unnest(array_remove(all_ctids, actid))
  FROM (
         SELECT
           min(b.ctid)     AS actid,
           array_agg(ctid) AS all_ctids
         FROM your_table b
         GROUP BY key1, key2, key3, key4
         HAVING count(*) > 1) c);

5voto

Zaytsev Dmitry Points 548

Une autre approche (qui ne fonctionne que si vous disposez d'un champ unique tel que id dans votre table) pour trouver tous les identifiants uniques par colonne et supprimer les autres identifiants qui ne sont pas dans la liste des identifiants uniques.

DELETE
FROM users
WHERE users.id NOT IN (SELECT DISTINCT ON (username, email) id FROM users);

3voto

NewBee Points 944

Postgresql possède la fonction Windows, vous pouvez utiliser rank() pour archiver votre objectif, échantillon :

WITH ranked as (
    SELECT
        id, column1,
        "rank" () OVER (
            PARTITION BY column1
            order by column1 asc
        ) AS r
    FROM
        table1
) 
delete from table1 t1
using ranked
where t1.id = ranked.id and ranked.r > 1

2voto

Barrie Walker Points 11

Que diriez-vous de.. :

WITH
  u AS (SELECT DISTINCT \* FROM your\_table),
  x AS (DELETE FROM your\_table)
INSERT INTO your\_table SELECT \* FROM u;

Je m'inquiétais de l'ordre d'exécution, si le DELETE se produisait avant le SELECT DISTINCT, mais cela fonctionne bien pour moi. De plus, il n'est pas nécessaire de connaître la structure de la table.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X