3张表:供应商(sid,sname,地址),零件(pid,pname,颜色),目录(sid,pid,成本)
找到所有供应每个零件的供应商的答案是:
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
)
)
有人可以向我解释这个答案吗?我只是有点迷路!
我听说它的解释是“寻找不存在的供应商
他们不出售的一部分”,但我正在努力寻找如何
SELECT C1.sid
FROM Catalog C1
WHERE C1.sid = C.sid
AND C1.pid = P.pid
)
完成了。
所以如果我有一个
目录表
詹姆斯|锤子
詹姆斯|砧
詹姆斯|扳手
亨利|锤子
乐华|砧
零件表
锤子
砧
扳手
那么在最里面的子句之后,到底返回了什么?
是吗
詹姆斯|锤子
詹姆斯|砧
詹姆斯|扳手
亨利|锤子
乐华|砧
然后不存在使它
詹姆斯| -
亨利|扳手铁砧
乐华|锤子,扳手?
零件表如何减去这些值?很抱歉,如果这些问题不太清楚,我还是SQL新手。
最佳答案
这是一个双嵌套的NOT EXISTS
查询(不,实际上,这是我通常看到的这种查询),它专门用于回答这种类型的问题,即“对所有y是否都有x真?”
Here's MySQL's page on EXISTS and NOT EXISTS,它专门提到了此技术。
首先,在最里面的SELECT
查询中,选择每个商店所携带的零件。然后,使用第一个NOT EXISTS
子句,选择每个商店都不携带的部件。最后,在外部NOT EXISTS
子句中,您选择的商店将为内部NOT EXISTS
子句返回空集,这意味着它们包含了每个部分。
此查询的Here is a SQLFiddle起作用。
:警告:如果您正在使用SQL,则最好按集合进行思考和工作,以线性方式思考(如将要遵循的内容)会使您迅速陷入困境。不要养成习惯!
但是,有时当试图找出像这样的复杂查询时,可以将这些事情视为循环。
因此,以小提琴中的数据为例,我们有:
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
因此,使用此数据,AAA承载木材和石材,BBB仅承载木材,而CCC承载木材,石材和纸张。
现在,让我们逐行浏览查询。我们从
suppliers
中进行选择,并确定要在结果集中包含哪些行,因此从suppliers
中的第一行开始:9,'AAA'
。我们将暂时将此行称为S
。如果内部结果集中没有任何内容,我们将仅包括该行,因此让我们看一下。suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
该结果集是从
parts
中选择的,我们将逐行对其进行遍历。在执行此操作时,S
仍等于9,'AAA'
。因此,从parts
的第一行开始:1,'wood'
。我们现在将其称为P
。如果下一级结果集中没有任何内容,我们将仅将此行包含在此第一个内部结果集中,因此让我们继续进行。请记住,S
= 9,'AAA'
和P
= 1,'wood'
。suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
P => 1, 'wood'
2, 'stone'
3, 'paper'
此最里面的查询是从“目录”中选择的。我们正在寻找任何行,我们将其称为
C
,在catalog
中,其中C.sid
等于S.sid
而C.pid
等于P.pid
。这意味着当前供应商承担了该零件。我们需要当前供应商不携带的零件,这就是我们反转结果集的原因。我们知道S
的sid为9,并且我们知道P
的pid为1。C
中是否有与此匹配的行? C
的第一行与之匹配,因此我们知道该结果集不为空。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
现在跳回到下一个最外层的循环。内部结果集不为空,因此我们知道
1,'wood
将不属于此循环的结果集。因此,我们移至parts
,2,'stone'
中的下一行。我们将P
的值更新为等于该行。我们应该在结果集中包括这一行吗?我们必须使用P
的新值再次运行内部查询(S
仍未更改)。因此,我们在catalog
中查找sid
等于9且pid
等于2的任何行。第二行匹配,因此有一个结果集。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
跳回到下一个最外层循环。内部结果集不为空,因此
2,'stone'
将不属于此循环的结果集。当我们再次遍历
3,'paper'
时,发现catalog
中没有包含sid = 9
和pid = 3
的行。最里面的结果集为空,因此我们知道在下一个最外面的循环中包含此P
值。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
至此,我们已经遍历了整个
parts
表,因此我们为第二个循环设置了最终结果集,并且它不为空,这意味着我们找到了S
不携带的部分,因此我们知道我们不能包括最终外循环结果集中S
的当前值。因此,我们转到
suppliers
中的下一行,并从头开始整个过程:suppliers:
sid, name
9, 'AAA'
S => 8, 'BBB'
7, 'CCC'
一旦到达
S = 7,'CCC'
,我们将遍历所有这些循环,并且将在内部循环中找到与所提供的每个P值匹配的内容,这意味着第二个循环将具有一个空集。我们找不到供应商不携带的任何零件,因此S
的值被添加到结果集中,这意味着他们可以携带一切!
关于sql - 查找提供每个零件的供应商的sid,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29012455/