为什么在SQL中不可避免地使用双嵌套NOT EXISTS语句

时间:2014-12-31 14:23:53

标签: mysql sql relational-division

这更多是出于好奇/科学兴趣,而不是基于一个真正的问题而我曾经向我的数据库讲师询问过这个问题,但他无法回答/理解我的问题。所以我决定过来。

编程语言应该是一种工具,工具可以使工作更轻松,对吧?那么为什么只需执行SELECT * FROM foo WHERE bar=42;即可在一个表中找到所有条目。但是,只要涉及多个表,就没有简单/直观的方式来说“找到符合此标准的所有元组”?

脚本中的给定示例是这样的(这是从德语翻译的,因此命名可能有点令人困惑):

对于以下格式的表:

  • 组分(的 CNR ,CNAME,颜色,重量,城市)
  • 项目(的 PNR 下,PNAME,城市)
  • SCP(的 SNR CNR PNR 下,数量)

以粗体显示的主键。该示例是关于运送到不同城市的不同项目的组件。

任务是编写一个查询,以查找发往一个特定城市中所有项目的所有组件。

给定的解决方案如下所示:

SELECT CNR
FROM components
WHERE NOT EXISTS ( SELECT 1
                  FROM project
                  WHERE project.city = 'Foobar Town'
                  AND NOT EXISTS ( SELECT 1
                                 FROM scp
                                 WHERE scp.PNR = projekt.PNR
                                 AND scp.CNR = components.CNR ));

我的意思是,它是正确的,有道理的,甚至是有效的。但它不直观,当然不会让生活更轻松!那么我想知道这个的原因在哪里?由于我们被告知这对考试至关重要,因此我们能够编写这样的查询,我无法学习它。

我还没有找到一个更简单的解决方案。既不是谷歌搜索也不是自己尝试。必须有一个更好的理由,而不是“每个人都懒得解决这个问题”。任何一个想法?

我们课程中给学生的示例和所有材料都基于SQL92。

感谢您的回答

1 个答案:

答案 0 :(得分:3)

您的问题是:“查找已发送到某个特定城市的所有项目的所有组件。”您将此描述为“查找给定城市中没有项目但没有该组件的所有组件。”

我更倾向于直接回答这个问题:

select scp.component
from scp join
     projects p
     on scp.pnr = p.pnr
where p.city = 'Foobar Town'
group scp.component
having count(distinct scp.pnr) = (select count(distinct pnr)
                                  from projects
                                  where city = 'Foobar Town'
                                 );

这会计算城市中不同项目的数量,并将它们与城市中的项目数量进行比较(子查询中可能不需要distinct id。

首先,我不确定这是否更简单。其次,我是第一个承认NOT EXISTS方法可能更高效的人,尽管NOT EXISTS在子查询中的嵌套可能会对性能产生不利影响。但是,我认为这更容易理解。