PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment supprimer les lignes en double avec des dépendances de clés étrangères ?

Vous pouvez le faire beaucoup plus efficacement avec une instruction SQL unique avec CTE modifiant les données .

WITH plan AS (
   SELECT *
   FROM  (
      SELECT recid, min(recid) OVER (PARTITION BY cdesc) AS master_recid
      FROM   cpt
      ) sub
   WHERE  recid <> master_recid  -- ... <> self
   )
 , upd_lab AS (
   UPDATE lab l
   SET    cpt_recid = p.master_recid   -- link to master recid ...
   FROM   plan p
   WHERE  l.cpt_recid = p.recid
   )
DELETE FROM cpt c
USING  plan p
WHERE  c.recid = p.recid
RETURNING c.recid;

db<>violon ici (page 11)
SQL Fiddle (page 9.6)

Cela devrait être beaucoup plus rapide et plus propre. Le bouclage est relativement coûteux, la gestion des exceptions est comparativement encore plus coûteuse.
Plus important encore, les références dans lab sont redirigés vers la ligne maître respective dans cpt automatiquement, ce qui n'était pas encore dans votre code d'origine. Ainsi, vous pouvez supprimer tous les doublons d'un coup .

Vous pouvez toujours envelopper cela dans une fonction plpgsql ou SQL si vous le souhaitez.

Explication

  1. Au 1er CTE plan , identifiez une ligne principale dans chaque partition avec le même cdesc . Dans votre cas, la ligne avec le minimum recid .

  2. Au 2ème CTE upd_lab rediriger toutes les lignes faisant référence à un dupe vers la ligne principale dans cpt .

  3. Enfin, supprimez les doublons, ce qui ne déclenchera pas d'exceptions car les lignes dépendantes sont liées à la ligne principale restante pratiquement en même temps.

ON DELETE RESTRICT

Tous les CTE et la requête principale d'un relevé fonctionnent sur le même instantané des tables sous-jacentes, pratiquement simultanément . Ils ne voient pas les effets les uns des autres sur les tables sous-jacentes :

On pourrait s'attendre à une contrainte FK avec ON DELETE RESTRICT pour lever des exceptions parce que, [selon la documentation][3] :

Cependant, la déclaration ci-dessus est une commande unique et, [le manuel encore][3] :

Bold emphase mienne. Fonctionne pour la valeur par défaut moins restrictive ON DELETE NO ACTION aussi, bien sûr.

Mais méfiez-vous des transactions simultanées écrivant dans les mêmes tables, mais c'est une considération générale, non spécifique à cette tâche.

Une exception s'applique pour UNIQUE et PRIMARY KEY contrainte, mais cela ne concerne ceci cas :