2015-03-12 1 views
2

3 tableaux: Fournisseurs (sid, sname, adresse), les parties (pid, pname, couleur), Catalogue (sid, pid, coût)Trouvez les SIDS des fournisseurs qui fournissent chaque partie

La réponse à trouver tous les fournisseurs qui fournissent chaque pièce est:

SELECT C.sid 
    FROM Catalog C 
    WHERE NOT EXISTS (
    SELECT P.pid 
     FROM Parts P 
     WHERE NOT EXISTS (
     SELECT C1.sid 
      FROM Catalog C1 
      WHERE C1.sid = C.sid 
      AND C1.pid = P.pid 
     ) 
    ) 

Est-ce que quelqu'un pourrait m'expliquer cette réponse? Je suis juste un peu perdu!

Je l'ai entendu expliqué que « fournisseurs Trouvez ce qu'il n'existe pas une partie qu'ils ne vendent pas », mais je me bats pour voir comment

SELECT C1.sid 
      FROM Catalog C1 
      WHERE C1.sid = C.sid 
      AND C1.pid = P.pid 
     ) 

qui accomplit.

Donc, si j'ai un

Tableau catalogue

James | Marteau

James | Enclume

James | Clé

Henry | Marteau

Leroy | Anvil

Partie Tableau

Marteau

enclume

Clé

Puis, après la clause la plus profonde ce qui est retourné exactement?

Est-il

James | Marteau

James | Enclume

James | Clé

Henry | Marteau

Leroy | Anvil

et NOT EXISTS rend

James | -

Henry | Enclume, clé

Leroy | Marteau, clé?

Comment la table Parts soustrait-elle ces valeurs? Désolé si ces questions ne sont pas trop claires, je suis encore nouveau sur SQL.

+0

Quel est le SGBDR que vous utilisez? –

+0

Désolé, je ne suis pas sûr de comprendre la question. Voulez-vous dire SQL? – tryingtolearn

+0

Non, quelle est votre DB? MSSQL ou MySQL ou tout autre DB? –

Répondre

5

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, catalogC.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!

+0

Je comprends. Pouvez-vous expliquer ce que la partie finale que j'ai souligné signifie? Comment (C1.sid = C.id ET C1.pid = P.pid) est différent de (C.pid = P.pid). Il semble évidemment différent mais je ne vois pas comment .. – tryingtolearn

+0

Les choses se sont un peu allongées, voir ma réponse élargie –

+0

Je pense que je peux le suivre un peu mieux. Cependant, dans les parties, O WH N'EXISTE PAS .. le SELECT le plus interne ne devrait-il pas être un attribut que partage la partie Parts? – tryingtolearn