SQL计划编译和真值表

标签 sql sql-server null left-join

如果我有 NOT ( 1 <> 1 AND NULL <> 1 )
我可以在执行计划 XML 中看到 SQL 将其转换为:( 1 = 1 OR NULL = 1)
如果您要从字面上计算前一个表达式,则 True AND Null将为 Null 并消除该行。但是,由于 OR,编译后的表达式可以返回一行。

我可以假设这种类型的编译一定会发生吗? SQL Server 永远不会尝试将复杂的逻辑引入编译计划?有关于这方面的一些文件吗?

这篇文章很有帮助,但我只是错过了一个难题:
https://www.simple-talk.com/sql/learn-sql-server/sql-and-the-snare-of-three-valued-logic/

这是一个 SQL 示例

SELECT 1
FROM T T
    LEFT JOIN T2 T2 --t2 has zero rows
        ON T.id = t2.t_id
WHERE NOT ( T.id <> 99 AND T2.id <> 99 )

根据我使用 SQL 的经验,我知道在正常情况下(没有短路评估) T2.id <> 99 有效地将左联接变成了内联接。这是我最初期望的行为。当这个过滤器真正起作用时,我感到很惊讶。

最佳答案

TL;博士 “编译结果”不是一个有用的概念。重要的是“指定结果”——由语言定义指定。 DBMS 必须使语句按照您编写的方式运行。

您链接中 AND 的真相 [原文如此] 表是错误的。在 SQL 中,AND with False 总是 False,OR with True 总是 True。

SQL 中的比较返回 True、False 或 Unknown。 Unknown 可能来自与 Unknown 上的 NULL 或 3VL 逻辑连接(AND/OR/NOT 等)的比较。 “NULL”不是文字。 True、False 和 Unknown 是 SQL 标准中具有(分类)文字的值,但在大多数 DBMS 中没有。 (并且 Unknown 可以返回为 NULL。) IS 不是比较; IS NULL 和 IS NOT NULL 是一元 3Vl 逻辑连接词,因此以 TRUE、FALSE 和 UNKNOWN 命名的类似连接词也是如此。它们总是返回 True 或 False。

True AND Null would be Null and would eliminate the row. However, the compiled expression can return a row due to the OR.



不。您链接中 AND 的真相 [原文如此] 表是错误的。在 SQL 中,AND with False 总是 False,OR with True 总是 True。因此,您的 AND 从 1 <> 1 的 False 的 AND 中的 NOT 的 NOT 中始终为 False,并且您的 OR 始终为 1 = 1 中的 True。无论其他比较返回什么(真、假或未知)。如果您使用 the (correct) SQL truth tables) 处理这两个表达式,它们总是给出相同的结果,True。

在 SQL 中重写条件必须非常小心。一个可以互换NOT (E1 *comparison* E2)来自 E1 *NOT-comparison* E2NOT (E IS ?)E IS NOT ? .如果没有任何值为 NULL 的值,则可以使用标准逻辑标识/规则安全地重写表达式。还可以安全地将重写规则应用于
    (E1 *comparison* E2)
AND E1 IS NOT NULL AND E2 IS NOT NULL

还要注意,您必须正确使用 Unknown 最终结果,其中包括不匹配 WHERE 但不匹配约束。

SELECT 1
FROM T T
    LEFT JOIN T2 T2 --t2 has zero rows
        ON T.id = t2.t_id
WHERE NOT ( T.id <> 99 AND T2.id <> 99 )


LEFT JOIN 返回 INNER JOIN 的行加上由 T2 列 NULL 扩展的 T 的不匹配行。 (当 T2 为空时,INNER JOIN 为空,T 的所有行都不匹配。)所有扩展行都有 T2.id <> 99 未知,因为 T2.id 为 NULL。对于 T.id = 99,AND 为 False,NOT 为 True; WHERE 返回所有行。对于 T1.id 任何其他整数或 NULL,AND 将是 Unknown,NOT 将是 Unknown; WHERE 不返回任何行。

(在 SQL 中没有对条件的“短路”评估。必​​须定义连接词的每个参数。)

关于SQL计划编译和真值表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34319415/

相关文章:

mysql - 微软 Access : How can I make multiple querys pull records from different tables into one list

c# - 为什么值类型不能为空

sql - 更新sql中前100行的随机数?

sql - 前 12 个月间隔和 ISO 周的平均值

.net - 客户端服务器安装包.NET

html - 在sql server客户端报告(rdlc)中渲染html代码

swift - 在 Swift 中填充字典

null - 表达式 "IS NOT NULL"不适用于 HQL

php - 尝试将 mysql select 语句转换为 PDO

sql - 在没有游标的情况下合并单个SQL表中的数据