找到供应每个部件的供应商的sids

时间:2015-03-12 14:27:51

标签: sql algebra relational

3个表:供应商(sid,sname,地址),部件(pid,pname,颜色),目录(sid,pid,cost)

找到供应每个部件的所有供应商的答案是:

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
         )

完成了。

所以,如果我有一个

目录表

詹姆斯|锤

詹姆斯|砧

詹姆斯|扳手

亨利|锤

Leroy |砧

部分表

铁砧

扳手

然后在最里面的子句之后返回了什么?

是吗

詹姆斯|锤

詹姆斯|砧

詹姆斯|扳手

亨利|锤

Leroy |砧

然后NOT EXISTS使它

詹姆斯| -

亨利|铁砧,扳手

Leroy |锤子,扳手?

零件表如何减去这些值?很抱歉,如果这些问题不太清楚,我仍然不熟悉SQL。

1 个答案:

答案 0 :(得分:5)

这是一个双重嵌套NOT EXISTS查询(实际上并不是我经常看到的那个问题),并且它专门用于回答这种类型的问题,即& #34;对于所有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'。从parts1,'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'

这个最里面的查询是从&#39;目录&#39;中选择的。我们正在查找任何行,我们会在C中将其称为catalog,其中C.sid等于S.sid并且C.pid等于{{ 1}}。这意味着当前供应商承担该部分。我们需要当前供应商提供的零件,这就是我们反转结果集的原因。我们知道P.pid的sid是9,我们知道S的pid是1. P中是否有与之匹配的行? <{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仍未更改)。因此,我们查找PS等于9且catalog等于2的所有行。第二行匹配,因此存在结果集。

sid

跳回下一个最外圈。内部结果集不为空,因此pid不会成为此循环结果集的一部分。

当我们再次对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,我们将遍历所有这些循环,并且将在内部循环中找到所提供的P的每个值的匹配,这意味着第二个循环将为空组。我们无法找到供应商无法携带的任何零件,因此suppliers: sid, name 9, 'AAA' S => 8, 'BBB' 7, 'CCC' 的值会添加到结果集中,这意味着它们可以随身携带!