【发布时间】:2020-07-24 03:34:15
【问题描述】:
我使用唯一约束来避免除空值之外的重复项,因为此列可以保持为空(它不是必填字段,但它有助于搜索,例如通过电子邮件搜索等)
在上述情况下,选择唯一约束是否正确?
替代方案 由于 unique 只允许一个空值,所以可以为唯一约束生成不同的默认值吗?即每一行都是唯一的。
【问题讨论】:
-
如果你想允许
NULL的重复并且正在使用 MySQL,那么唯一约束不会做你想要的。
我使用唯一约束来避免除空值之外的重复项,因为此列可以保持为空(它不是必填字段,但它有助于搜索,例如通过电子邮件搜索等)
在上述情况下,选择唯一约束是否正确?
替代方案 由于 unique 只允许一个空值,所以可以为唯一约束生成不同的默认值吗?即每一行都是唯一的。
【问题讨论】:
NULL 的重复并且正在使用 MySQL,那么唯一约束不会做你想要的。
您同时标记了sqlite 和mysql 的问题,所以我将同时介绍这两个问题。
在 SQLite 中,UNIQUE 约束将按您的意愿工作。
UNIQUE constraint 的文档说:
出于 UNIQUE 约束的目的,NULL 值被认为与所有其他值不同,包括其他 NULL 。
CREATE INDEX 的文档说:
如果 UNIQUE 关键字出现在 CREATE 和 INDEX 之间,则不允许重复的索引条目。任何插入重复条目的尝试都将导致错误。出于唯一索引的目的,所有 NULL 值都被认为与所有其他 NULL 值不同,因此是唯一的。这是对 SQL-92 标准的两种可能解释之一(标准中的语言是模棱两可的),也是 PostgreSQL、MySQL、Firebird 和 Oracle 遵循的解释。 Informix 和 Microsoft SQL Server 遵循该标准的其他解释。
但是,在大多数其他数据库中,UNIQUE 约束的列不能为 NULL,因此我建议使用 UNIQUE INDEX 代替,以保持一致性,以免混淆。
在 MySQL 中,UNIQUE 约束将按您的意愿工作。
Unique Indexes 的文档说:
UNIQUE索引允许多个NULL值用于可包含NULL的列。
唯一键是唯一索引的同义词。
如 SQLite 文档中所述,Microsoft SQL Server 对 UNIQUE 索引的 NULL 处理遵循不同的解释。
UNIQUE INDEX 的文档说:
唯一索引中使用的列应设置为 NOT NULL,因为在创建唯一索引时多个空值被视为重复。
要解决这个问题,请使用过滤索引,例如
CREATE UNIQUE INDEX Person_Email
ON Person ( Email )
WHERE Email IS NOT NULL;
【讨论】:
您可以对生成的列使用技巧。像这样的:
alter table t add unique_val as
( concat(coalesce(col, ''), ':', (case when col is null then pk end)) ) unique;
其中pk 是主键列。
这会将NULL 值替换为每行上已知的唯一值。
【讨论】: