在撰写本文时,这个问题的标题是
SQL NOT IN约束和NULL值
从问题的文本来看,问题似乎发生在SQL DML SELECT查询中,而不是SQL DDL约束中。
然而,特别是考虑到标题的措辞,我想指出这里所做的一些陈述是潜在的误导性陈述,那些沿着(意译)
当谓词求值为UNKNOWN时,您不会得到任何行。
尽管这是SQL DML的情况,但当考虑约束时,效果是不同的。
考虑一下这个非常简单的表,其中有两个约束条件直接来自问题中的谓词(@Brannon的回答很好):
DECLARE @T TABLE
(
true CHAR(4) DEFAULT 'true' NOT NULL,
CHECK ( 3 IN (1, 2, 3, NULL )),
CHECK ( 3 NOT IN (1, 2, NULL ))
);
INSERT INTO @T VALUES ('true');
SELECT COUNT(*) AS tally FROM @T;
根据@Brannon的回答,第一个约束(使用IN)计算为TRUE,第二个约束(使用非IN)计算为UNKNOWN。但是,插入成功了!因此,在这种情况下,严格地说“您没有得到任何行”是不正确的,因为我们确实得到了一行插入作为结果。
上述效果对于SQL-92标准来说确实是正确的。比较和对比SQL-92规范中的以下部分
7.6 where条款
的结果是T的那些行组成的表
其中搜索条件的结果为真。
4.10完整性约束
表检查约束当且仅当指定
表中任何一行的查询条件都不为false。
换句话说:
在SQL DML中,当WHERE值为UNKNOWN时,将从结果中删除行,因为它不满足条件“is true”。
在SQL DDL(即约束)中,当行计算为UNKNOWN时,不会从结果中删除,因为它确实满足条件“不为假”。
尽管在SQL DML和SQL DDL中的效果分别看起来可能是矛盾的,但有一个实际的理由让UNKNOWN结果“受益于怀疑”,允许它们满足约束(更准确地说,允许它们不满足约束):没有这种行为,每个约束都必须显式地处理空值,从语言设计的角度来看,这将是非常令人不满意的(更不用说,对程序员来说是一个痛苦!)
附注:如果你发现像我写的那样遵循“未知不满足约束”这样的逻辑具有挑战性,那么你可以考虑通过避免SQL DDL中可空列和SQL DML中任何产生空值的列(例如外部连接)来省去这一切!