为啥 SQL 中无法避免双重嵌套的 NOT EXISTS 语句

Posted

技术标签:

【中文标题】为啥 SQL 中无法避免双重嵌套的 NOT EXISTS 语句【英文标题】:Why are double nested NOT EXISTS statements unavoidable in SQL为什么 SQL 中无法避免双重嵌套的 NOT EXISTS 语句 【发布时间】:2014-12-31 14:23:53 【问题描述】:

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

编程语言应该是一种工具,而工具是为了让工作更轻松,对吧?那么为什么您可以通过简单地执行SELECT * FROM foo WHERE bar=42; 在一个表中找到所有条目。但是一旦涉及到多个表,就没有简单/直观的方式来说“找到所有满足此条件的元组”?

脚本中给定的示例是这样的(这是从德语翻译过来的,所以命名可能有点混乱):

对于以下格式的表格:

组件(CNR,Cname,Color,Weight,City) 项目(PNR,Pname,City) 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 的。

感谢您的回答

【问题讨论】:

这是一种可能的解决方案。如果您想使用更直观的解决方案,请使用一个 - 但如果您希望我们找到一个,那么您必须定义“直观” 直观地说,我的意思是“给我这个”的直截了当的陈述,就像你只在一张桌子上操作一样。像上面的解决方案这样的陈述是相当困难的。主要是因为双重否定。无论是通过谷歌搜索还是自己尝试,我都找不到更简单的方法。所以这一定是有原因的。 在我看来原因是您的解决方案需要证明是否定的。 SQL 设置为易于获得肯定:“获取满足此条件的所有结果”。但是您需要“获取此条件没有例外的所有结果”。如果你能想出一种重新发明 SQL 的方法,让它直观地做到这两点,你可能会成为下一个亿万富翁,但我认为这不会像你想象的那么容易。 “给定的解决方案”并没有像你想象的那样做。建立一些表并进行测试。 如果我没记错的话,查询会执行所谓的关系除法,为什么从未实施过特定的关系操作对我来说是个谜;我们确实得到了联合、交叉和差异,但从来没有分裂。也许实施起来太难了。不过set1 divided by set2 会很好。 【参考方案1】:

您的问题是:“查找已运往/已运往某个特定城市的所有项目的所有组件。”您将其改写为“查找给定城市中没有项目但没有该组件的所有组件。”

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

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 可能会损害性能。不过,我确实认为这更容易理解。

【讨论】:

我喜欢你避免否定的方式,我支持你,当你在几周后回到这个问题时,它会让你更容易理解。 是的,对我来说更容易理解。所以这实际上是可能的,尽管我们被告知并非如此。只要我有时间回到那个练习,我就会测试这个。还有很多其他的事情要做。所以这可能需要几天时间。谢谢你的回答。我会将其标记为已解决

以上是关于为啥 SQL 中无法避免双重嵌套的 NOT EXISTS 语句的主要内容,如果未能解决你的问题,请参考以下文章

避免在 PL/SQL 中从双重联合中选择

对齐双重包裹的嵌套 flex

python中为啥我的for循环里嵌套的if只能循环一次?

为啥批量收集到子句限制了 pl/sql 中嵌套表的大小

为啥使用动态 ptr 数组检测到分段错误或双重释放?

为啥实体框架会生成嵌套 SQL 查询?