Il s'agit d'une double requête imbriquée NOT EXISTS
(pas vraiment, c'est ce que j'ai souvent vu), et elle est utilisée spécifiquement pour répondre à ce type de quesion, "Existe-t-il un x vrai pour tout?"
Here's MySQL's page on EXISTS and NOT EXISTS, qui mentionne cette technique spécifique.
Tout d'abord, dans la requête SELECT
plus à l'intérieur, vous choisissez des pièces que chaque magasin offre. Puis, avec la première NOT EXISTS
clause, vous choisissez des pièces qui ne sont pas exécutées par chaque magasin. Enfin, dans la clause NOT EXISTS
externe, vous sélectionnez les magasins qui a renvoyé un ensemble vide pour la clause NOT EXISTS
intérieure, ce qui signifie qu'ils transportent chaque partie.
Here is a SQLFiddle de cette requête en action.
Un mot d'avertissement: si vous travaillez avec SQL, il est toujours bon de penser et de travailler dans des ensembles, et penser en termes linéaires comme ce qui va suivre peut vous causer des ennuis rapidement. Ne fais pas ça une habitude!
Cependant, parfois en essayant de comprendre une requête complexe comme celle-ci, il peut être utile de considérer ces choses comme des boucles.
Ainsi, en prenant les données dans le violon à titre d'exemple, nous avons:
suppliers:
sid, name
9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
1, 'wood'
2, 'stone'
3, 'paper'
catalog:
cid, pid, sid
1,1,9
2,2,9
3,1,8
4,1,7
5,2,7
6,3,7
Donc, avec ces données, AAA porte le bois et la pierre, BBB porte uniquement le bois et la CCC porte le bois, la pierre, et papier.
Passons maintenant à la requête ligne par ligne. Nous sélectionnons à partir de suppliers
, et nous décidons des lignes à inclure dans le jeu de résultats, donc commencez par la première ligne en suppliers
: 9,'AAA'
. Nous appellerons cette ligne S
temporairement. Nous n'inclurons cette ligne que s'il n'y a rien dans le jeu de résultats interne, alors jetons un oeil à cela.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
Ce jeu de résultats est la sélection de parts
, et nous allons passer par ligne par ligne. S
est toujours égal à 9,'AAA'
pendant que nous faisons cela. Commencez donc avec la première ligne en parts
: 1,'wood'
. Nous appellerons cette ligne P
pour le moment. Nous n'inclurons cette ligne que dans ce premier jeu de résultats interne s'il n'y a rien dans le prochain niveau de jeu de résultats, alors allons-y. Rappelez-vous que S
= 9,'AAA'
et P
= 1,'wood'
.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
P => 1, 'wood'
2, 'stone'
3, 'paper'
Cette requête la plus interne est sélectionnée dans 'catalogue'. Nous cherchons n'importe quelle ligne, nous l'appellerons C
, catalog
où C.sid
est égal à S.sid
et C.pid
est égal à P.pid
. Cela signifie que le fournisseur actuel porte la pièce. Nous voulons des pièces que le fournisseur actuel ne porte pas, c'est pourquoi nous inversons le jeu de résultats. Nous savons que le sid de S
est 9, et nous savons que le pid de P
est 1. Y a-t-il des lignes dans C
qui correspondent à cela? La toute première ligne de C
correspond à cela, donc nous savons que ce jeu de résultats n'est pas vide.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
P => 1, 'wood'
2, 'stone'
3, 'paper'
catalog:
cid, pid, sid
C => 1,1,9 --Match found! Don't include P in outer result set
2,2,9
3,1,8
4,1,7
5,2,7
6,3,7
Revenez maintenant à la prochaine boucle la plus à l'extérieur. Le jeu de résultats interne n'était pas vide, nous savons donc que 1,'wood
ne fera pas partie du jeu de résultats de cette boucle. Nous passons donc à la ligne suivante parts
, 2,'stone'
.Nous mettons à jour la valeur de P
pour égaler cette ligne. Devrions-nous inclure cette ligne dans le jeu de résultats? Nous devons réexécuter la requête interne avec notre nouvelle valeur pour P
(S
n'a toujours pas changé). Nous cherchons donc toutes les lignes catalog
avec sid
égale à 9 et pid
égale à 2. La deuxième ligne correspond, donc il y a un ensemble de résultats.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
1, 'wood'
P => 2, 'stone'
3, 'paper'
catalog:
cid, pid, sid
1,1,9
C => 2,2,9 --Match found! Don't include P in outer result set
3,1,8
4,1,7
5,2,7
6,3,7
Revenez à la prochaine boucle la plus à l'extérieur. Le jeu de résultats interne n'était pas vide, donc 2,'stone'
ne fera pas partie du jeu de résultats de cette boucle.
Quand nous traversons tout cela encore pour 3,'paper'
, nous constatons qu'il n'y a pas de lignes de catalog
qui ont sid = 9
et pid = 3
. Le jeu de résultats le plus interne est vide, donc nous savons inclure cette valeur de P
dans la boucle la plus externe.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
1, 'wood'
2, 'stone'
P => 3, 'paper'
catalog:
cid, pid, sid
1,1,9
2,2,9
3,1,8
4,1,7
5,2,7
6,3,7
C => --No match found, include P in outer result set
Nous sommes passés par l'ensemble de la table parts
à ce stade, nous avons donc notre résultat final fixé pour la deuxième boucle, et ce n'est pas vide, ce qui signifie que nous avons trouvé une partie qui S
ne transporte pas, nous savons donc que nous ne pouvons pas inclure la valeur actuelle de S
dans l'ensemble de résultats de notre boucle externe finale.
Nous passons donc à la ligne suivante suppliers
et commencer le processus sur:
suppliers:
sid, name
9, 'AAA'
S => 8, 'BBB'
7, 'CCC'
Une fois que nous arrivons à S = 7,'CCC'
nous allons passer par toutes ces boucles, et un match se trouve dans le boucle interne pour chaque valeur de P fournie, ce qui signifie que cette seconde boucle aura un ensemble vide. Nous n'avons pas trouvé de pièces que le fournisseur ne porte pas, de sorte que la valeur de S
est ajoutée au jeu de résultats, ce qui signifie qu'ils portent tout!
Quel est le SGBDR que vous utilisez? –
Désolé, je ne suis pas sûr de comprendre la question. Voulez-vous dire SQL? – tryingtolearn
Non, quelle est votre DB? MSSQL ou MySQL ou tout autre DB? –