如果子查询没有返回结果,为啥“= ALL(子查询)”评估为真?

Posted

技术标签:

【中文标题】如果子查询没有返回结果,为啥“= ALL(子查询)”评估为真?【英文标题】:Why does "= ALL (subquery)" evaluate to true if the subquery returnes no results?如果子查询没有返回结果,为什么“= ALL(子查询)”评估为真? 【发布时间】:2021-12-09 10:15:18 【问题描述】:

如果子查询没有返回任何结果,我希望“= ALL (subquery)”的计算结果为 false。

但是在测试中我发现情况并非如此:

--put one record in #Orders
SELECT 1 AS 'OrderID'
INTO #Orders;

--put one record in #OrderLines
SELECT
    1 AS 'OrderID'
    ,1 AS 'OrderLineID'
    ,3 AS 'Quantity'
INTO #OrderLines;

--as expected this returns the record in #Orders
SELECT *
FROM #Orders
WHERE 3 = ALL
    (
    SELECT Quantity
    FROM #OrderLines
    );

--now delete the record in #OrderLines
DELETE FROM #OrderLines;

--this still returns the record from #Orders even though the subquery returns no results
SELECT *
FROM #Orders
WHERE 3 = ALL
    (
    SELECT Quantity
    FROM #OrderLines
    );

最终select语句的执行计划:https://www.brentozar.com/pastetheplan/?id=H1jQ2YgIK

测试日期:

Microsoft SQL Server 2017 (RTM-CU20) (KB4541283) - 14.0.3294.2 (X64) Microsoft SQL Server 2017 (RTM-CU25) (KB5003830) - 14.0.3401.7 (X64)

在搜索时,我发现非官方来源说如果子查询没有返回结果,则“= ALL(子查询)”的计算结果为 true:

“ALL 必须以比较运算符开头,如果查询没有返回任何行,则计算结果为 TRUE”https://dotnettutorials.net/lesson/all-operator-sql-server/

“ALL 必须以比较运算符开头,如果查询没有返回任何行,则计算结果为 TRUE”https://www.w3resource.com/sql/special-operators/sql_all.php

但我在官方文档 (https://docs.microsoft.com/en-us/sql/t-sql/language-elements/all-transact-sql?view=sql-server-ver15) 中没有看到任何支持该想法的内容,实际上它似乎对此提出异议:"ALL 要求 scalar_expression 与返回的每个值进行正比较通过子查询"

问题

    如果子查询未返回任何结果,SQL Server 中的预期行为是否会将 ALL 评估为真? 如果#1 的答案是“是”: 它是否记录在某处? 这种行为的解释是什么?在上面的代码示例中,3 没有与没有结果进行正面比较,因此查询应该返回结果似乎非常不直观

感谢您的帮助和见解。

【问题讨论】:

我怀疑这是文档中的遗漏;如果是这样,您最好通过在文档的 GitHub 上提出问题来查询事实。不过,我必须承认,ALL 很少使用。大多数人更喜欢使用NOT EXISTS 之类的东西。 您引用的 document 声明:“结果值当所有对 (scalar_expression,x) 的比较指定为 TRUE 时返回 TRUE,当x 是单列集中的值。否则返回 FALSE。魔鬼的拥护者:如果没有返回行,那么比较 not TRUE 是哪一行?广告中的真相:Microsoft PowersHell。 我了解只有在子查询中至少有一个值与比较不匹配时,ALL 才会返回 false。所以,是的,我认为这是预期的行为。 关于这种行为的解释,请看***.com/a/2195428/11683。 这能回答你的问题吗? ALL operator VS Any on an empty query 【参考方案1】:

转述documentation:

...如果子查询的某些值不符合表达式的条件,scalar_expression = ALL (subquery) 将评估为 FALSE。

这很微妙,但是如果 some 值确实满足条件,则意图似乎是返回 false,否则返回 true。在没有值的边缘情况下,没有不满足条件的值,所以返回true。

导致可能令人惊讶的结果的“问题”是单词“some”,它暗示存在。如果不存在值,则不可能有“某些”值是假的,所以它是真的。

您可以说它基于双重否定逻辑,其中边缘情况恰好落在结果的意外一半。


顺便说一句,我在职业生涯中编写了大量 SQL,但从未使用过这个关键字,也没有见过它使用过。

建议:不要使用。

【讨论】:

以上是关于如果子查询没有返回结果,为啥“= ALL(子查询)”评估为真?的主要内容,如果未能解决你的问题,请参考以下文章

oracle对表的基本操作

ThetaSome_ThetaAll子查询

如果子查询的结果为 NULL,MySQL 整个查询将失败

(My)SQL:如果子查询不是空集,则返回子查询

如果子查询在 MySQL 中返回多于 1 行,如何将 JSON 放入列数据中

如果子关系在 Laravel 中有结果,我如何只返回父级,如果关系是三重嵌套的?