2010-02-04 12 views
2

J'avais suis maintenant une requête qui est la suivante:.Quelqu'un peut-il expliquer pourquoi sur terre ces requêtes ne sont pas les mêmes?

select field_1, field_2 
from source_table 
minus 
select field_1, field_2 
from source_table 
where status_code in (3, 600); 

Quand je regardais cette requête, je pensais tout de suite, «C'est boiteux Pourquoi ne pas simplement utiliser un « NOT IN » et retirez l'entreprise MINUS. donc, je re-écrit comme ceci:

select field_1, field_2 
from source_table 
where status_code not in (3, 600); 

Juste pour revérifier ma santé mentale, je suis arrivé compte de chaque requête à ma grande surprise, la première requête a retourné 789,089 enregistrements, et la deuxième requête a retourné 1,518,450 records.!

J'ai regardé cela à partir de sever mais ne peut pas comprendre comment ces deux requêtes sont différentes. Quelqu'un peut-il expliquer ce qui se passe, ou pourquoi je suis un idiot ce matin?

+0

Voulez-vous publier les plans pour les deux requêtes. – EvilTeach

Répondre

9

Ces requêtes sont en effet différentes. field_1 et field2 ne correspondent pas à status_code 3 et 600. field_1 pourrait être «A» et field_2 pourrait être «B», de sorte que vous élimineriez les enregistrements du premier SELECT qui ressemblent A, B. L'original est probablement le meilleur moyen d'obtenir le bon résultat.

Edit: Pour vous donner une meilleure idée de ce qui se passe, vous pouvez obtenir le même résultat, de façon similaire à la façon dont vous pensiez à écrire la requête, en faisant une sous-requête:

select distinct field_1, field_2 
from source_table 
where (field_1, field_2) not in (
    select field_1, field_2 
    from source_table 
    where status_code in (3, 600) 
); 
+0

Ah, juste eu un moment d'ampoule. Merci pour l'aide! –

+0

Ce n'est toujours pas identique. MINUS est une commande set et fera implicitement un distinct. Vous auriez besoin d'ajouter cela au remplacement. –

+0

@Gary Merci. J'ai changé le SQL en conséquence. –

3

Si vous n'avez pas une contrainte unique sur field_1, field_2 ou les deux, Alison a probablement raison. Considérez que vous avez une table: A B 3 A B 10

La première requête éliminerait les deux lignes, la deuxième une seule. Alternativement, si vous avez des valeurs NULL dans la colonne status_code, vous pouvez obtenir des résultats différents, (A ou non A) ne fonctionne pas dans SQL si vous avez des valeurs NULL dans les colonnes.

4

S'il n'y a pas de contrainte unique sur la combinaison de field_1 et field_2, la deuxième requête peut contenir des doublons alors que la première ne le fera pas, car 'minus' les supprimera. Essayez la deuxième requête avec un 'distinct' et voyez si les comptes correspondent.

4

Les opérateurs UNION, MINUS et INTERSECT ne renvoient que des valeurs uniques. Si vous avez deux lignes avec field_1 et field_2 identiques, la première requête comptera une fois, tandis que la deuxième comptera deux fois:

SQL> insert into source_table values ('a', 'b', 10); 

SQL> insert into source_table values ('a', 'b', 10); 

SQL> select field_1, field_2 
    2 from source_table 
    3 minus 
    4 select field_1, field_2 
    5 from source_table 
    6 where status_code in (3, 600); 

FIELD_1 FIELD_2 
---------- ---------- 
a   b 

SQL> select field_1, field_2 
    2 from source_table 
    3 where status_code not in (3, 600); 

FIELD_1 FIELD_2 
---------- ---------- 
a   b 
a   b 
+0

Ah, ce détail fait une grande différence. J'avais oublié ça. Merci! –

+0

Bien que si c'était l'histoire complète, on pourrait simplement insérer DISTINCT et être fait avec. Mais, comme le montrent certains articles ci-dessus, ce n'est pas l'histoire complète (mais un point valable bien sûr). –