Answers:
为什么这样工作?因为可以追溯到那时,有人在不知道或不关心标准说什么的情况下做出了一个设计决策(毕竟,我们确实有各种带有NULL
s 的怪异行为,并且可以随意强迫不同的行为)。在这种情况下,该决定要求NULL = NULL
。
这不是一个非常明智的决定。他们应该做的是使默认行为符合ANSI标准,如果他们确实想要这种特殊行为,请通过DDL选项(例如WITH CONSIDER_NULLS_EQUAL
或)允许它WITH ALLOW_ONLY_ONE_NULL
。
当然,事后看来是20/20。
无论如何,即使不是最干净或最直观的解决方案,我们也都有解决方法。
通过创建唯一的筛选索引,可以在SQL Server 2008及更高版本中获得适当的ANSI行为。
CREATE UNIQUE INDEX foo ON dbo.bar(key) WHERE key IS NOT NULL;
这允许一个以上的NULL
值,因为这些行被完全排除在重复检查之外。作为额外的好处,如果NULL
允许多个s,则最终它的索引将小于包含整个表的索引(特别是当它不是索引中的唯一列,具有INCLUDE
列等时)。但是,您可能需要了解筛选索引的其他一些限制:
正确。在sql server中,唯一约束或索引的实现只允许一个NULL。还要更正这一点,从技术上讲,它与NULL的定义不符,但这是他们做的事情之一,即使它在“技术上”不正确,也使其更有用。请注意,PRIMARY KEY(也是唯一索引)不允许使用NULL(当然)。
首先-停止使用短语“空值”,它只会使您误入歧途。而是使用短语“空标记”(null marker)-列中的标记,指示该列中的实际值缺失或不适用(但请注意,该标记并未说明实际上是哪种选择¹)。
现在,想象以下情况(数据库不完全了解建模情况)。
Situation Database
ID Code ID Code
-- ----- -- -----
1 A 1 A
2 B 2 (null)
3 C 3 C
4 B 4 (null)
我们正在建模的完整性规则是“代码必须唯一”。现实情况违反了这一点,因此数据库不应同时将表2和表4都放在表中。
最安全,最不灵活的方法是在“代码”字段中禁止使用空标记,因此不可能出现数据不一致的情况。最灵活的方法是允许多个空标记,并在输入值时担心唯一性。
Sybase程序员采用了一种比较安全,不太灵活的方法,即只允许在表中使用一个空标记-此后,评论员一直在抱怨。我猜微软是为了保持向后兼容性而继续这种行为。
¹我确信我读过某个地方,科德考虑实现两个空标记-一个用于未知,一个用于不适用-但拒绝了它,但我找不到参考。我记得正确吗?
PS我最喜欢的关于null的报价是:Louis Davidson,“ Professional SQL Server 2000数据库设计”,Wrox出版社,2001,第52页。
null
也不能实现这个目标。因为丢失的值可能与其他行之一中的值相同。
CHECK (Value IN ('A','B','C','D'))
怎么办?然后,SQL-Server的实现和SQL标准都允许表具有5行(每个值一行,外加1个NULL)。然后,可以说,虽然数据库与其约束一致,但与设计者的意图不一致。该表格最多包含4行。没有可以将NULL更改为不会违反约束的值,除非删除一个或多个行。
CREATE TABLE #T(A INT NULL UNIQUE);INSERT INTO #T VALUES (1),(NULL);UPDATE #T SET A = 1 WHERE A IS NULL;
会引发错误。根据您的设计动机理论,应该NULL
在第一种情况下避免插入-因为知识的不完整意味着无法保证其价值是不同的。
从技术上讲这可能不准确,但从哲学上讲,它可以帮助我晚上入睡。
就像其他人已经说过或暗示过的,如果您认为NULL是未知的,则无法确定一个NULL值实际上是否等于另一个NULL值。以这种方式考虑,表达式NULL == NULL应该计算为NULL,表示未知。
唯一性约束将需要确定的值来比较列值。换句话说,当使用相等运算符将单个列值与任何其他列值进行比较时,它必须评估为false才有效。尽管未知通常被认为是虚假的,但它并不是真的错误。两个NULL值可以相等,也可以不相等...根本无法确定。
这有助于将唯一约束视为可以确定为彼此不同的限制值。我的意思是,如果您运行的SELECT看起来像这样:
SELECT * from dbo.table1 WHERE ColumnWithUniqueContraint="some value"
鉴于存在唯一约束,大多数人会期望得到一个结果。如果在ColumnWithUniqueConstraint中允许多个NULL值,则不可能使用NULL作为比较值从表中选择单个不同的行。
鉴于此,我相信,不管是否按照NULL的定义正确实现了它,在大多数情况下,它绝对比允许多个NULL值实际得多。
UNIQUE
约束的主要目的之一是防止重复记录。如果需要一张表,其中可以有多个记录的值是“未知”,但不允许两个记录具有相同的“已知”值,那么在对未知值进行分配之前,应该为其分配人工唯一标识符添加到表格中。
在极少数情况下,列具有UNIQUE
约束并且包含单个null值;例如,如果一个表包含列值和本地化文本描述之间的映射,则使用一行NULL
可以定义当其他表中的该列为时应显示的描述NULL
。的行为NULL
允许该使用情况。
否则,我看不到UNIQUE
在任何列上都有约束以允许存在许多相同记录的数据库的基础,但是在允许键值不可区分的多个记录时,我看不到任何防止这种情况的方法。声明NULL
不等于自身不会使NULL
值彼此区分。