【问题标题】:Really hard time understanding this query真的很难理解这个查询
【发布时间】:2015-10-11 04:47:50
【问题描述】:

以下查询应该返回“预订了所有船只的水手”

这是 mySQL 代码

SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS 
    ((SELECT B.bid  
     FROM Boats B)
    Except
    (SELECT R.bid  
     FROM Reserves R
     WHERE R.sid = S.sid))

我只是……不知道如何阅读它。我知道“NOT EXISTS”后面的子查询应该返回 Boats 表中所有记录的船 ID(出价)。因此,Except 后面的查询应该返回所有已预订船只的船 ID……这意味着如果有人预订了所有船只,则不应返回任何内容,这意味着 NOT EXISTS 将评估为 true 并且它将只给那个水手的名字?我认为这是让我感到困惑的最后一部分......它最终如何返回水手的名字?

【问题讨论】:

  • 我不知道 MySQL 支持 EXCEPT 子句
  • @Strawberry 很有趣。我的教授让我们下载 MySQL 服务器来练习执行 SQL 查询,但她给了我们非 MySQL 示例(比如这个)。叹息。
  • @shA.t 这是我的教授给我的查询。我更喜欢..它所做的事情的英文翻译而不是更正它..我相信子查询会返回所有尚未保留的船 ID。所以当我读到“NOT EXISTS”时,NOT EXISTS 应用于什么?什么是不存在的?是说“找到所有未保留的船ID表中不存在的sname吗?”如果该表本身没有 snames(只有船 ids),它如何获得任何返回的名称?

标签: mysql sql nested-queries


【解决方案1】:

我们有一些船可以由水手预订,水手已经注册并且我们知道他们,所以表格的结构是:

[Table: Boats]          [Table: Sailors]        [Table: Reserves]
+-----+--------+        +-----+----------+      +-----+-----+-----+
| bid | bname  |        | sid | sname    |      | rid | bid | sid |
+-----+--------+        +-----+----------+      +-----+-----+-----+
| 1   | Boat 1 |        | 1   | Sailor 1 |      | 1   | 1   | 1   |
| 2   | Boat 2 |        | 2   | Sailor 2 |      | 2   | 2   | 3   |
| 3   | Boat 3 |        | 3   | Sailor 3 |      +-----+-----+-----+
+-----+--------+        +-----+----------+

在上述数据中,当你需要知道哪些船没有预订时;你可以使用下面的查询,它会给你出价 => 3:

SELECT B.bid  FROM Boats B
EXCEPT
SELECT R.bid  FROM Reserves R;

当您需要知道哪些船没有(曾经)被水手预订时;您可以使用下面的查询,为 sid = 3 提供出价 => [1, 3]:

SELECT B.bid  FROM Boats B
EXCEPT
SELECT R.bid  FROM Reserves R  WHERE R.[sid] = 3;

当水手预订所有船只时,上述查询将没有结果,因此NOT EXISTS(<above query>) 将为真。现在您可以使用上面的查询来找到保留所有船只的水手,如下所示:

SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS (
    SELECT B.bid  FROM Boats B
    EXCEPT
    SELECT R.bid  FROM Reserves R
    WHERE R.[sid] = S.[sid]);

所以如果Reserves 的数据变成这样:

 [Table: Reserves]
 +-----+-----+-----+
 | rid | bid | sid |
 +-----+-----+-----+
 | 1   | 1   | 1   |
 | 2   | 2   | 1   |
 | 3   | 3   | 1   |
 +-----+-----+-----+

您的查询将给出Sailor 1 的结果;)。


更多信息:
EXCEPT 从左输入查询返回右输入查询未输出的不同行。
EXISTS:指定一个子查询来测试是否存在行。

【讨论】:

  • 即将通读,但最后,当您定义 EXCEPT 时,不应该说“从左输入查询返回由右输入查询输出的不同行”吗? @shA.t
  • @FrostyStraw It comes from here
  • 好的,所以..以下是否不正确:NOT EXISTS 是否一一应用于水手的每一行?例如,对于 sid = 1,它会在 NOT EXISTS 内进行查询,如果没有返回任何行,它只会返回与该 id 匹配的水手的姓名?然后会去sid = 2(假设多个水手可以同时预订一艘船),如果没有再次返回行,则返回匹配sid = 2的水手姓名,否则继续sid = 3,等等等等? @shA.t
  • 我可以说是的; DBMS 做得如此接近它;您可以通过手动设置外部值的值(如 S.[sid]) 的测试来检查 EXISTS 的内部选择的验证;)。
【解决方案2】:

你可以改造sql,subselect

(SELECT B.bid  
 FROM Boats B)
Except
(SELECT R.bid  
 FROM Reserves R
 WHERE R.sid = S.sid)

应该和

一样
(SELECT B.bid  
 FROM Boats B
 WHERE B.sid <> S.sid)

如果你替换你得到的主 sql 中的部分

SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS 
(SELECT B.bid  
 FROM Boats B
 WHERE B.sid <> S.sid)

只选择那些没有其他sid的船的水手,这与“预订所有船的水手”相同

【讨论】:

    猜你喜欢
    • 2020-12-02
    • 1970-01-01
    • 2012-03-22
    • 2012-12-17
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多