SUPPRIMER les lignes qui ne sont pas référencées dans une autre table

15

J'ai deux tables dans une base de données PostgreSQL 9.3: la table link_replya une clé étrangère nommée which_grouppointant vers la table link_group.

Je souhaite supprimer toutes les lignes d' link_groupoù aucune ligne associée link_replyn'existe. Cela semble assez basique mais j'ai eu du mal avec.

Sera-ce quelque chose de simple comme ça (ne fonctionne pas)?

DELETE FROM link_group WHERE link_reply = NULL;
Hassan Baig
la source
avez-vous un DDL pour tout le monde à regarder?
dizzystar
Jetez un œil à l'opérateur MINUS. Vous devez spécifier un champ dans links_reply.
Vérace
DELETE FROM links_group USING links_group AS lg LEFT JOIN links_reply AS lr ON lg.col= lr.some_other_col WHERE links_reply.some_other_col IS NULL
Mihai
J'avais une question similaire, qui prend également en compte la simultanéité. Voir dba.stackexchange.com/questions/251875 .
pbillen

Réponses:

19

Citant le manuel:

Il existe deux façons de supprimer des lignes dans une table en utilisant les informations contenues dans d'autres tables de la base de données: en utilisant des sous-sélections ou en spécifiant des tables supplémentaires dans la USINGclause . La technique la plus appropriée dépend des circonstances spécifiques.

Accentuation sur moi. L'utilisation d'informations qui ne sont pas contenues dans une autre table est un peu délicate, mais il existe des solutions faciles. De l'arsenal des techniques standards au ...

... une NOT EXISTSanti-semi-jointure est probablement la plus simple et la plus efficace pour DELETE:

DELETE FROM link_group lg
WHERE  NOT EXISTS (
   SELECT FROM link_reply lr
   WHERE  lr.which_group = lg.link_group_id
   );

En supposant (puisque les définitions de table ne sont pas fournies) link_group_idcomme nom de colonne pour la clé primaire de link_group.

La technique @Mihai commentée fonctionne également (appliquée correctement):

DELETE FROM link_group lg
USING  link_group      lg1
LEFT   JOIN link_reply lr ON lr.which_group = lg1.link_group_id
WHERE  lg1.link_group_id = lg.link_group_id
AND    lr.which_group IS NULL;

Mais comme l'expression de table dans la USINGclause est jointe à la table cible ( lgdans l'exemple) avec un CROSS JOIN, vous avez besoin d'une autre instance de la même table que le tremplin ( lg1dans l'exemple) pour le LEFT JOIN, qui est moins élégant et généralement plus lent.

Erwin Brandstetter
la source