谁能解释第二次选择的结果。我期望第一行data1(1,'1')不在data2?
with data1(id, val) as
(select 1, '1' from dual union all
select 2, '2' from dual),
data2(id, val) as
(select 1, null from dual union all
select 2, '2' from dual)
select id, val
from data1
where (id, val) IN (select id, val from data2);
-- Result (as expected):
-- id, val
-- 2 '2'
with data1(id, val) as
(select 1, '1' from dual union all
select 2, '2' from dual),
data2(id, val) as
(select 1, null from dual union all
select 2, '2' from dual)
select id, val
from data1
where (id, val) NOT IN (select id, val from data2)
-- No Result ???
即。第一行(1,'1')既不是IN数据2也不是IN数据2?
答案 0 :(得分:4)
首先是一点理论:Null (SQL)
从以上链接中我们最重要的部分:
与NULL和三值逻辑(3VL)的比较
由于Null不是任何数据域的成员,因此不被视为a “值”,而是表示缺席的标记(或占位符) 有价值的。因此,与Null的比较永远不会导致 无论是真还是假,但始终是第三个逻辑结果, 未知的。[8]比较下面表达式的逻辑结果 10到Null的值是Unknown:
SELECT 10 = NULL -- Results in Unknown
这样两个比较:x = NULL
和x <> NULL
的计算结果为NULL(未知)。
SQL实现三个逻辑结果,因此SQL实现必须 提供专门的三值逻辑(3VL)。规则 管理SQL三值逻辑如下表所示(p和 q表示逻辑状态)“[9] SQL用于AND,OR的真值表 并且不对应于Kleene和Łukasiewicz的常见片段 三值逻辑(它们对含义的定义不同, 但是SQL没有定义这样的操作。)
+---------+-------------+-------------+-------------+-----------+--------+ | p | q | p OR q | p AND q | p = q |p != q | +---------+-------------+-------------+-------------+-----------+--------+ | True | True | True | True | True | False | | True | False | True | False | False | True | | True | Unknown | True | Unknown | Unknown | Unknown| | False | True | True | False | False | True | | False | False | False | False | True | False | | False | Unknown | Unknown | False | Unknown | Unknown| | Unknown | True | True | Unknown | Unknown | Unknown| | Unknown | False | Unknown | False | Unknown | Unknown| | Unknown | Unknown | Unknown | Unknown | Unknown | Unknown| +---------+-------------+-------------+-------------+-----------+--------+
WHERE子句中未知的效果
数据操作语言中遇到SQL三值逻辑 (DML)比较DML语句和查询的谓词。的的 WHERE子句导致DML语句仅对那些行起作用 谓词评估为True。
简而言之:WHERE子句将NULL视为FALSE
现在请考虑一个更简单的案例:
SELECT * FROM T1;
| X |
|--------|
| 1 |
| (null) |
和查询:
SELECT * FROM t1 WHERE x IN (1, NULL);
以上查询是这个问题的缩写:
SELECT * FROM t1
WHERE x = 1
OR x = NULL
对于表t
的第二行(x = NULL),这个条件如下:
WHERE NULL = 1
OR NULL = NULL
因此行x=NULL
的此条件求值为NULL,因为NULL=1
为NULL,NULL=NULL
为NULL,NULL OR NULL
也为NULL(请参阅上面的表3VL) )。
现在考虑更好奇的案例:
SELECT * FROM t1 WHERE x NOT IN (1, NULL);
此条款x NOT IN (1, NULL)
相当于NOT ( x IN (1, NULL) )
所以它也相当于:
NOT (
x = 1
OR
x = NULL
)
根据De Morgan's laws,它相当于:
NOT ( x = 1 ) AND NOT ( x = NULL )
和(如果我们将NOT x = y
替换为x <> y
),它也相当于:
x <> 1 AND x <> NULL
请仔细查看最后一个条件:
WHERE
x <> 1 AND x <> NULL
我们知道,x <> NULL
总是评估为NULL。我们也从上面的3VL表中知道,true AND NULL
都是NULL而false AND NULL
的计算结果为FALSE,因此整个条件总是计算为FALSE或NULL,但它永远不会计算为TRUE。
因此具有以下条件的查询:
SELECT .....
WHERE x NOT IN ( NULL, whatever)
始终返回空结果集
现在你的查询,也很好奇:
SELECT * FROM t1
WHERE (id, val) NOT IN (select id, val from data2);
可以重写(使用常量值):
SELECT * FROM t1
WHERE (id, val) NOT IN (
(1, null),
(2, 2 )
)
此查询使用所谓的row value expression
基本上是使用像这样的行值表达的条件
(a, b) = (x, y)
相当于这一个:
a = x AND b = y
所以上面的查询可以重写为这个:
SELECT * FROM t1
WHERE NOT (
id = 1 AND val = NULL
OR
id = 2 AND val = 2
)
根据De Morgan的法律,这与以下内容相同:
SELECT * FROM t1
WHERE
NOT ( id = 1 AND val = NULL )
AND
NOT ( id = 2 AND val = 2 )
并进一步:
SELECT * FROM t1
WHERE
( id <> 1 OR val <> NULL )
AND
( id <> 2 OR val <> 2 )
由于条件的第一部分( id <> 1 OR val <> NULL )
仅在id <> 1
的情况下评估为真(请参见上面的3VL表),因此可以将此条件简化为:
SELECT * FROM t1
WHERE
( id <> 1 )
AND
( id <> 2 OR val <> 2 )
并进一步(根据De Morgan的法律)进入:
SELECT * FROM t1
WHERE
id <> 1 AND id <> 2
OR
id <> 1 AND val <> 2
因此来自(1,1)
的{{1}}和(2,2)
都不符合这些条件。
答案 1 :(得分:1)
处理空值时,最好使用NOT EXISTS而不是NOT IN。 这是来自asktom的帖子,解释了原因:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::no::p11_question_id:442029737684