web-dev-qa-db-fra.com

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

J'ai deux tables dans une base de données PostgreSQL 9.3: Table link_reply possède une clé étrangère nommée which_group pointant vers le tableau link_group.

Je souhaite supprimer toutes les lignes de link_group où aucune ligne associée dans link_reply 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;
15
Hassan Baig

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 clause USING. La technique la plus appropriée dépend des circonstances spécifiques.

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

... une NOT EXISTS l'anti-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_id comme nom de colonne pour la clé primaire de link_group.

La technique @ Mihai a commenté fonctionne aussi (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 puisque l'expression de table dans la clause USING est jointe à la table cible (lg dans l'exemple) avec un CROSS JOIN, vous avez besoin d'une autre instance de la même table que le tremplin (lg1 dans l'exemple) pour le LEFT JOIN, qui est moins élégant et généralement plus lent.

19