如果我有NOT ( 1 <> 1 AND NULL <> 1 )
我可以看到SQL在执行计划XML中将其转换为:( 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;DR "编译结果"不是一个有用的概念。重要的是"指定的结果"——由语言定义指定。DBMS 必须使语句按照您编写的方式运行。
您链接中 AND 的真相 [原文如此] 表是错误的。在 SQL 中,带有 False 的 AND 始终是 False,而带有 True 的 OR 始终是 True。
SQL 中的比较返回真、假或未知。未知可能来自与 NULL 或未知上的 3VL 逻辑连接(和/或/非等(的比较。"NULL"不是字面意思。True,False和Unknown是SQL标准中带有(分类(文字的值,但在大多数DBMS中不是。 (Unknown可以返回为NULL。IS不是比较;IS NULL 和 IS NOT NULL 是一元 3Vl 逻辑连接词,以 TRUE、FALSE 和 UNKNOWN 命名的类似连接词也是如此。它们总是返回 True 或 False。
True AND Null
将为 Null 并将消除该行。然而, 编译的表达式可以返回由于 OR 而返回一行。
不。您链接中 AND 的真相 [原文如此] 表是错误的。在 SQL 中,带有 False 的 AND 始终是 False,而带有 True 的 OR 始终是 True。因此,您的 AND 始终是 False,从 1 <> 1 的 AND 中从 FALSE 的 NOT 变为 False,而您的 OR 从 1 = 1 开始始终为真。无论其他比较返回什么(真、假或未知(。如果使用(正确的(SQL 真值表处理这两个表达式,则它们始终给出相同的结果 True。
在SQL中重写条件时必须非常小心。可以通过E1 *NOT-comparison* E2
或NOT (E IS ?)
和E IS NOT ?
交换NOT (E1 *comparison* E2)
。如果没有值为 NULL,则可以使用标准逻辑标识/规则安全地重写表达式。还可以安全地将重写规则应用于
(E1 *comparison* E2)
AND E1 IS NOT NULL AND E2 IS NOT NULL
另请注意,您必须正确使用未知最终结果,其中包括不匹配 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 为空时,内部联接为空,并且 T 的所有行都不匹配。所有扩展行都 T2.id <> 99 未知,因为 T2.id 为 NULL。对于 T.id = 99,AND 为假,NOT 为真;WHERE 返回所有行。对于 T1.id 任何其他整数或 NULL,AND 将为"未知",NOT 将为"未知";WHERE 不返回任何行。
(在SQL中没有对条件的"短ciruit"评估。必须定义连接词的每个参数。
如果从字面上计算前一个表达式,则 True AND Null 将为 Null,并将消除该行。
不。您正在评估表达式。 NOT ( 1 <> 1 AND NULL <> 1 )
是NOT (FALSE AND UNKNOWN)
是NOT FALSE
是TRUE
。
( 1 = 1 OR NULL = 1)
是TRUE OR UNKNOWN
是TRUE
.它们都是等效的。
NOT ( 1 <> 1 AND NULL <> 1 )
可以重写为 NOT ((NOT (1=1)) AND (NOT (NULL = 1)))
.在正则的两个值逻辑中,由德摩根定律可以重写为NOT (NOT ((1 = 1) OR (NULL = 1)))
然后(1=1) OR (NULL = 1)
。事实证明,德摩根定律也适用于SQL的三个值逻辑。这可以通过为这两个定律创建详尽的真值表来证明。
真值表显示德摩根定律之一,(NOT A) OR (NOT B)
等价于NOT (A AND B)
,在SQL的三个值逻辑中成立:
A B | (NOT A) OR (NOT B) | equiv? | NOT (A AND B)
========================================================
T T | F T F F T | T | F T T T
T F | F T T T F | T | T T F F
T U | F T U U U | T | U T U U
-------------------------------------------------------
F T | T F T F T | T | T F F T
F F | T F T T F | T | T F F F
F U | T F T U U | T | T F F U
-------------------------------------------------------
U T | U U U F T | T | U U U T
U F | U U T T F | T | T U F F
U U | U U U U U | T | U U U U
另一个定律,(NOT A) AND (NOT B)
等同于NOT (A OR B)
同样可以证明。
不我可以假设这种类型的编译保证总是发生吗?
,从不(几乎从不(保证特定的编译。除非 SQL Server 中存在错误,否则所选的查询计划、应用的转换将返回查询指定的结果。
编辑补充:让T.id
99
,T2.id
NULL
。然后:
-
WHERE NOT ( T.id <> 99 AND T2.id <> 99 )
-
WHERE NOT (99 <> 99 AND NULL <> 99)
-
WHERE NOT (FALSE AND UNKNOWN)
-
WHERE NOT (FALSE)
-
WHERE TRUE