【问题标题】:Converting From NOT EXISTS to NOT IN从 NOT EXISTS 转换为 NOT IN
【发布时间】:2014-12-29 02:55:55
【问题描述】:

我有三张桌子:

  • sailor(姓名、评分);
  • boat(名称、颜色、评级);
  • reservation(sname、bname、工作日、开始、结束);

为了得到预订每艘红船的水手名单,我有:

select s.sname from sailor s 
where not exists(  
    select * from boat b  
    where b.color = 'red'  
    and not exists (  
        select * from reservation r  
        where r.bname = b.bname  
        and r.sname = s.sname));

我现在需要用 NOT IN 而不是 NOT EXISTS 重写这个查询。到目前为止,这是我所拥有的:

select s.sname from sailor s
where s.sname not in (select s2.sname from sailor s2 where
    s2.sname not in (select r.sname from reservation r where r.bname not in (
            select b.bname from boat b where b.color <> 'red' )));

然而,这会返回所有预订红船的水手的列表(不一定是全部)。我很难检查列表中的名称是否保留了每艘船(我也不能使用 COUNT())。

感谢任何帮助

【问题讨论】:

  • 您是否遇到任何错误?
  • 没有 SQL 错误,但是当我使用 NOT IN 运行第二个查询时,我得到了每个租用红色船的水手的列表,这与每个租用每条船的水手不同。对于这个问题,我很难把注意力集中在 NOT IN 逻辑上。
  • 如果你想找到租了所有船的水手,那么这个条件需要什么where b.color = 'red'
  • 很抱歉;我已经编辑了原始帖子。我正在尝试获取预订每艘 RED 船的水手列表,这是我的第一个查询所做的。
  • 双重NOT EXISTS(...) 结构有什么问题?这是处理像您这样的关系划分问题的标准方法。在大多数情况下,它优于 IN (...),因为它可以优雅地处理 NULL,并且不需要抑制重复。

标签: sql database relational-database relational-division


【解决方案1】:

这很有趣;您可以在将 NOT EXISTS ( ... ) 替换为 IN ( ...) 时保持句法结构(相关子查询):

SELECT s.sname from sailor s
WHERE 13 NOT IN (
    SELECT 13 FROM boat b
    WHERE b.color = 'red'
    AND 42 NOT IN (
        SELECT 42 from reservation r
        WHERE r.bname = b.bname
        AND r.sname = s.sname
       )
    );

【讨论】:

  • 13 和 42 是做什么的?它们像临时变量吗?
  • @user2619824: x NOT IN (SELECT x FROM ...) 与 NOT EXISTS (SELECT * FROM ...) 的含义相同。如果 SELECT * FROM ... 中有任何行,则 SELECT x 返回一个带有 x 的行,否则它不返回任何行。 13s 和 42s 可能都只是 1。值无关紧要,因为我们只关心是否有值,即每个 SELECT * 中是否有一行。
  • 它们只是文字。子查询要么产生 13,要么根本不产生任何结果。因此,如果我们将结果与 13 进行比较,我们要么得到 TRUE,要么没有什么可比较的。这与 not exixts() 几乎相同,它自己解析为布尔值。 (当然 42 也类似)
【解决方案2】:

为了获得预订每艘船的水手名单。我会使用这个脚本

解决方案 1:

 ;WITH k AS 
    (
    SELECT b.sname,COUNT(distinct a.bname) coun FROM boat a
    INNER JOIN reservation b 
        on a.bname = b.bname
    GROUP BY b.sname
    )
    SELECT k.sname FROM k WHERE coun = (select COUNT(*) FROM boat AS b)

解决方案 2:

SELECT s.sname
FROM   sailor AS s
WHERE  s.sname NOT IN (SELECT DISTINCT a.sname
                       FROM   (SELECT s.sname,
                                      b.bname
                               FROM   sailor AS s
                                      CROSS JOIN boat AS b
                               WHERE  b.color = "Red") a
                       WHERE  a.sname + a.bname 
                                            NOT IN (SELECT r.sname + r.bname
                                                    FROM   reservation AS r
                                                    WHERE  r.sname IS NOT NULL
                                                            AND r.bname IS NOT NULL));

【讨论】:

  • 感谢您的回复。不过,我必须使用嵌套的 NOT IN(并且没有 COUNT())
  • 检查我的第二个解决方案
  • 不工作,很遗憾。这将返回每个水手的列表。船颜色红色需要检查,但是当我在交叉连接后添加检查时,它仍然不起作用
  • 我已经更新了原帖。我实际上是在寻找预订每艘 RED 船的每个水手的名单。对此感到抱歉。
  • 你也不需要那种丑陋的字符串连接。 WHERE a.sname NOT IN (SELECT r.sname FROM reservation AS r WHERE r.sname IS NOT NULL AND r.bname = a.bname ) 会起作用。
猜你喜欢
  • 2014-09-03
  • 2013-11-18
  • 2016-02-11
  • 2021-10-12
  • 2015-07-06
  • 2014-07-18
  • 2021-10-02
  • 2015-02-20
  • 2017-01-08
相关资源
最近更新 更多