存在与不存在查询误区?
Exist and Not Exists Query Misunderstanding?
考虑以下产品数据库架构:
Parts
(pid, pname)
Suppliers
(sid, sname)
Catalog
(sid, pid)
Catalog
中的 sid
是外键并引用 Suppliers
和 Catalog
中的 pid
是外键并引用 Parts
table。 (s1, p1)
在 Catalog
table 显示供应商 s1
生产 p1
.
如果我想查找某些供应商未提供的 Parts
的详细信息,我们该怎么做?我读了一些部分如下:
SELECT *
FROM parts P
WHERE ....... (SELECT S.sid
FROM suppliers
WHERE .....
(SELECT *
FROM catalog C
WHERE s.sid = C.sid AND P.pid = C.pid))
我的问题是 - 为什么一开始?我们使用 exist,其次……我们使用 not exist?
是不是就这么简单?如果不是,请使用我的示例表并指定您的预期输出:
DECLARE @Parts TABLE(pid INT, pname VARCHAR(100));
DECLARE @Suppliers TABLE(sid INT, sname VARCHAR(100));
DECLARE @Catalog TABLE(pid INT, sid INT);
INSERT INTO @Parts VALUES(1,'Part 1'),(2,'Part 2'),(3,'Part 3'),(4,'Part 4');
INSERT INTO @Suppliers VALUES(1,'Suppl 1'),(2,'Suppl 2'),(3,'Suppl 3');
INSERT INTO @Catalog VALUES(1,1),(1,3) --part 1 from two suppliers
,(2,1) --part 2 from one supplier
--part 3 no supplier
--part 4 no supplier
--Get all parts *that not supplied by some suppliers*
SELECT *
FROM @Parts AS p
WHERE p.pid NOT IN(SELECT c.pid FROM @Catalog AS c)
结果
pid pname
3 Part 3
4 Part 4
编辑:"your" 查询也达到了同样的效果,但这会表现更差:
此查询正在寻找 没有 供应商,确实 在 "catalog" 中有条目的零件。我必须承认,这闻起来有点像家庭作业:-)
SELECT * FROM @Parts P
WHERE NOT EXISTS (SELECT S.sid
FROM @Suppliers S
WHERE EXISTS (SELECT 1
FROM @Catalog C
WHERE s.sid = C.sid AND P.pid = C.pid
)
)
If I want find details of Parts
that are not supplied by some suppliers, how we can do this?
如果您想要 "details for parts where there exists a supplier that doesn't supply that part",那么您的查询 EXISTS
然后 NOT EXISTS
是正确的。
My problem is via - why at first? We use exist and in second ... we use not exist?
我会解释为什么"details for parts where there exists a supplier that doesn't supply that part"可以给出你的查询。 (使用 EXISTS
然后 NOT EXISTS
。)
A table 持有使某些 谓词(陈述模板)成为真实的 命题(陈述)的行:
Parts
"part P.pid is named P.pname"
Suppliers
"supplier S.sid is named S.sname"
Catalog
"supplier C.sid supplies part C.pid"
您需要为您的结果表达谓词。您希望 P.pid
-P.pname
行从以下内容中做出正确的陈述:
"part P.pid is named P.pname"
AND EXISTS S.sid ["supplier S.sid is named something"
AND NOT "supplier S.sid supplies part P.pid"]
但是我们必须用给定的谓词(加上条件和逻辑运算符)来表达这个谓词,这样DBMS才能计算出满足它的行:
"part P.pid is named P.pname"
AND EXISTS S.sid [EXISTS S.sname "supplier S.sid is named S.sname"
AND NOT EXISTS C.sid, C.pid [
"supplier C.sid supplies part P.pid" AND C.sid = S.sid AND C.pid = P.pid]]
现在转换为 SQL:
- T 的初始 谓词变为
FROM
T
- AND T 的谓词变为
JOIN
T
- AND 条件变为
WHERE
condition
或ON
condition
- 最外层的 EXISTS 删除的列 变为
SELECT
kept columns
- 其他 EXISTS T 的所有列 [T] 的谓词变为
EXISTS (
T
)
SELECT *
FROM Parts P
WHERE EXISTS (SELECT S.sid FROM Suppliers S
WHERE NOT EXISTS (SELECT 1 FROM Catalog C
WHERE C.sid = S.sid AND C.pid = P.pid))
PS你的问题原"details of parts that are not supplied by some suppliers"是unclear/ambiguous。这可能意味着 P.id
-P.pname
对,其中:
- "the parts are not supplied by all the suppliers"(同意你的解释SQL)
- "the parts are not not supplied (by any of the suppliers)"(与
中两个SQL版本的解释一致
"the parts don't have multiple suppliers"
SELECT * FROM Parts P
WHERE NOT EXISTS (SELECT *
FROM Catalog C1 JOIN Catalog C2 ON C1.sid <> C2.sid
AND C1.pid = P.pid AND C2.pid = P.pid)
如果你有 Parts
1-4 和 Suppliers
1-3 那么上面给出了三个不同的答案:
INSERT INTO Catalog VALUES (1,1),(2,1),(2,2),(3,1),(3,2),(3,3);
PPS 以上逻辑公式为:
-- 1. "the parts are not supplied by all the suppliers"
P(P.pid, P.pname)
AND EXISTS S.sid, S.sname [S(S.sid, S.sname) AND NOT C(S.sid, P.pid)]
-- 2 "the parts are not supplied (by some of the suppliers)"
P(P.pid, P.pname) AND NOT EXISTS C.sid C(C.sid, P.pid)
-- 3. "the parts don't have multiple suppliers"
P(P.pid, P.pname)
AND NOT EXISTS C1.sid, C2.sid
[C(C1.sid, P.pid) AND C(C2.sid, P.pid) AND C1.sid <> C2.sid]
考虑以下产品数据库架构:
Parts
(pid, pname)Suppliers
(sid, sname)Catalog
(sid, pid)
Catalog
中的 sid
是外键并引用 Suppliers
和 Catalog
中的 pid
是外键并引用 Parts
table。 (s1, p1)
在 Catalog
table 显示供应商 s1
生产 p1
.
如果我想查找某些供应商未提供的 Parts
的详细信息,我们该怎么做?我读了一些部分如下:
SELECT *
FROM parts P
WHERE ....... (SELECT S.sid
FROM suppliers
WHERE .....
(SELECT *
FROM catalog C
WHERE s.sid = C.sid AND P.pid = C.pid))
我的问题是 - 为什么一开始?我们使用 exist,其次……我们使用 not exist?
是不是就这么简单?如果不是,请使用我的示例表并指定您的预期输出:
DECLARE @Parts TABLE(pid INT, pname VARCHAR(100));
DECLARE @Suppliers TABLE(sid INT, sname VARCHAR(100));
DECLARE @Catalog TABLE(pid INT, sid INT);
INSERT INTO @Parts VALUES(1,'Part 1'),(2,'Part 2'),(3,'Part 3'),(4,'Part 4');
INSERT INTO @Suppliers VALUES(1,'Suppl 1'),(2,'Suppl 2'),(3,'Suppl 3');
INSERT INTO @Catalog VALUES(1,1),(1,3) --part 1 from two suppliers
,(2,1) --part 2 from one supplier
--part 3 no supplier
--part 4 no supplier
--Get all parts *that not supplied by some suppliers*
SELECT *
FROM @Parts AS p
WHERE p.pid NOT IN(SELECT c.pid FROM @Catalog AS c)
结果
pid pname
3 Part 3
4 Part 4
编辑:"your" 查询也达到了同样的效果,但这会表现更差:
此查询正在寻找 没有 供应商,确实 在 "catalog" 中有条目的零件。我必须承认,这闻起来有点像家庭作业:-)
SELECT * FROM @Parts P
WHERE NOT EXISTS (SELECT S.sid
FROM @Suppliers S
WHERE EXISTS (SELECT 1
FROM @Catalog C
WHERE s.sid = C.sid AND P.pid = C.pid
)
)
If I want find details of
Parts
that are not supplied by some suppliers, how we can do this?
如果您想要 "details for parts where there exists a supplier that doesn't supply that part",那么您的查询 EXISTS
然后 NOT EXISTS
是正确的。
My problem is via - why at first? We use exist and in second ... we use not exist?
我会解释为什么"details for parts where there exists a supplier that doesn't supply that part"可以给出你的查询。 (使用 EXISTS
然后 NOT EXISTS
。)
A table 持有使某些 谓词(陈述模板)成为真实的 命题(陈述)的行:
Parts
"part P.pid is named P.pname"Suppliers
"supplier S.sid is named S.sname"Catalog
"supplier C.sid supplies part C.pid"
您需要为您的结果表达谓词。您希望 P.pid
-P.pname
行从以下内容中做出正确的陈述:
"part P.pid is named P.pname"
AND EXISTS S.sid ["supplier S.sid is named something"
AND NOT "supplier S.sid supplies part P.pid"]
但是我们必须用给定的谓词(加上条件和逻辑运算符)来表达这个谓词,这样DBMS才能计算出满足它的行:
"part P.pid is named P.pname"
AND EXISTS S.sid [EXISTS S.sname "supplier S.sid is named S.sname"
AND NOT EXISTS C.sid, C.pid [
"supplier C.sid supplies part P.pid" AND C.sid = S.sid AND C.pid = P.pid]]
现在转换为 SQL:
- T 的初始 谓词变为
FROM
T
- AND T 的谓词变为
JOIN
T
- AND 条件变为
WHERE
condition
或ON
condition
- 最外层的 EXISTS 删除的列 变为
SELECT
kept columns
- 其他 EXISTS T 的所有列 [T] 的谓词变为
EXISTS (
T
)
SELECT *
FROM Parts P
WHERE EXISTS (SELECT S.sid FROM Suppliers S
WHERE NOT EXISTS (SELECT 1 FROM Catalog C
WHERE C.sid = S.sid AND C.pid = P.pid))
PS你的问题原"details of parts that are not supplied by some suppliers"是unclear/ambiguous。这可能意味着 P.id
-P.pname
对,其中:
- "the parts are not supplied by all the suppliers"(同意你的解释SQL)
- "the parts are not not supplied (by any of the suppliers)"(与
"the parts don't have multiple suppliers"
SELECT * FROM Parts P WHERE NOT EXISTS (SELECT * FROM Catalog C1 JOIN Catalog C2 ON C1.sid <> C2.sid AND C1.pid = P.pid AND C2.pid = P.pid)
如果你有 Parts
1-4 和 Suppliers
1-3 那么上面给出了三个不同的答案:
INSERT INTO Catalog VALUES (1,1),(2,1),(2,2),(3,1),(3,2),(3,3);
PPS 以上逻辑公式为:
-- 1. "the parts are not supplied by all the suppliers"
P(P.pid, P.pname)
AND EXISTS S.sid, S.sname [S(S.sid, S.sname) AND NOT C(S.sid, P.pid)]
-- 2 "the parts are not supplied (by some of the suppliers)"
P(P.pid, P.pname) AND NOT EXISTS C.sid C(C.sid, P.pid)
-- 3. "the parts don't have multiple suppliers"
P(P.pid, P.pname)
AND NOT EXISTS C1.sid, C2.sid
[C(C1.sid, P.pid) AND C(C2.sid, P.pid) AND C1.sid <> C2.sid]