存在与不存在查询误区?

Exist and Not Exists Query Misunderstanding?

考虑以下产品数据库架构:

Catalog 中的

sid 是外键并引用 SuppliersCatalog 中的 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 的初始 谓词变为 FROMT
  • AND T 的谓词变为 JOINT
  • AND 条件变为WHEREconditionONcondition
  • 最外层的 EXISTS 删除的列 变为 SELECTkept 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 对,其中:

  1. "the parts are not supplied by all the suppliers"(同意你的解释SQL)
  2. "the parts are not not supplied (by any of the suppliers)"(与
  3. 中两个SQL版本的解释一致
  4. "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]