2008-09-29 5 views

Répondre

42
select * from a where id not in (select a_id from b) 

Ou comme d'autres personnes sur ce sujet dit:

select a.* from a 
left outer join b on a.id = b.a_id 
where b.a_id is null 
2

select * d'un où id pas (sélectionnez a_id de b)

+1

Cela sera extrêmement coûteux car le moteur doit générer la sous-requête dans son intégralité avant de pouvoir commencer à éliminer les tuples de a. Pas une bonne idée en général. – dland

10
select * from a 
left outer join b on a.id = b.a_id 
where b.a_id is null 
+0

Je pense que cette jointure externe gauche fonctionnera beaucoup mieux que la clause 'in', à moins que l'optimiseur de requêtes ne les traite de la même manière ... – Codewerks

+0

Cela fonctionne à peu près. Vérifiez-le. –

+0

Ouais, intéressant, le plan de requête a un strep supplémentaire (Filter) pour la jointure gauche et le 'where in' est résolu en un 'droit anti semi join' ... quoi que ce soit ... – Codewerks

5

Une autre approche:

select * from a where not exists (select * from b where b.a_id = a.id) 

L'approche «existe» est utile si Il existe une autre clause "where" que vous devez joindre à la requête interne.

1

Vous obtiendrez probablement beaucoup de meilleures performances (que l'utilisation de « non ») si vous utilisez une jointure externe:

select * from a left outer join b on a.id = b.a_id where b.a_id is null; 
0

Une autre façon de l'écrire

select a.* from a left outer join b on a.id = b.id where b.id is null

Aïe, battu par Nathan :)

0

Cela vous protégera contre les valeurs nulles dans la clause IN, ce qui peut provoquer un comportement inattendu.

select * d'un où id pas (sélectionnez [a id] de b où [un id] est non nulle)

+0

Vous êtes mieux d'utiliser une jointure externe gauche plutôt que d'utiliser un prédicat IN en premier lieu. – dland

+0

Une raison de cette opinion? –

3
SELECT id FROM a 
EXCEPT 
SELECT a_id FROM b; 
+0

Le mot-clé 'EXCEPT' est' MINUS' dans Oracle. – onedaywhen

0

Dans le cas d'une jointure, il est assez rapide, mais quand nous supprimons des enregistrements de la base de données qui a environ 50 millions d'enregistrements et 4 jointures et plus en raison de clés étrangères, il faut quelques minutes pour le faire. plus rapide d'utiliser OU PAS EN condition comme ceci:

select a.* from a 
where a.id NOT IN(SELECT DISTINCT a_id FROM b where a_id IS NOT NULL) 
//And for more joins 
AND a.id NOT IN(SELECT DISTINCT a_id FROM c where a_id IS NOT NULL) 

Je recommande également cette approche pour la suppression dans le cas où nous n'avons pas supprimer configurés en cascade. Cette requête ne prend que quelques secondes.

0

La première approche est

select a.* from a where a.id not in (select b.ida from b) 

la seconde approche est

select a.* 
    from a left outer join b on a.id = b.ida 
    where b.ida is null 

La première approche est très coûteuse. La deuxième approche est meilleure.

Avec PostgreSQL 9.4, j'ai fait la fonction "explain query" et la première requête comme un coût de cost = 0.00 ..1982043603,32. Au lieu de cela la requête de jointure en tant que coût de coût = 45946.77..45946.78

Par exemple, je recherche tous les produits qui ne sont pas compatibles avec aucun véhicule. J'ai 100k produits et plus de 1m de compatibilité. La requête de jointure a passé environ 5 secondes, mais la version de la sous-requête n'a jamais été terminée au bout de 3 minutes.

Questions connexes