sql - 查找提供每个零件的供应商的sid

标签 sql algebra relational

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.sidC.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将不属于此循环的结果集。因此,我们移至parts2,'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 = 9pid = 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/

相关文章:

sql - 迭代删除重复记录

sql - 嵌套行组上的 SSRS 边框

sql - 微软 Access SQL : use update and replace to remove multiple spaces with a single one

computer-science - 抽象代数与程序设计

c++ - 尽可能快地比较 (a + sqrt(b)) 形式的两个值?

javascript - 仅在象限 I 和 IV 的圆周上均匀分布点

mysql n 到 m 查询

mysql - 如何在一个查询中每天包含多个 COUNT?

database - 如何将表格转换为rdf图?

comparison - 为什么此 verilog 关系语句返回 true?