主键中允许NULL - 为什么以及在哪个DBMS中?

Gen*_*нин 19 database database-design terminology relational-database

继我的问题"为什么在TSQL中使用'not null primary key'?" ...

正如我从其他讨论中所理解的,一些RDBMS(例如SQLite, MySQL的)允许主键中的"唯一"NULL.

为什么允许这样做以及它有何用处?

背景:我认为与同事和数据库专业人员进行沟通有助于了解不同DBMS中基本概念,方法及其实现的差异.

笔记

  • MySQL被修复并返回到"NOT NULL PK"列表.
  • SQLite已被添加(感谢Paul Hadfield)到"NULL PK"列表:

为了确定主键值的唯一性,NULL值被认为与所有其他值不同,包括其他NULL.

如果INSERT或UPDATE语句尝试修改表内容,以便两个或多个行具有相同的主键值,则会违反约束.根据SQL标准,PRIMARY KEY应始终表示NOT NULL.不幸的是,由于长期的编码监督,在SQLite中并非如此.

除非列是INTEGER PRIMARY KEY,否则SQLite允许在PRIMARY KEY列中使用NULL值.我们可以改变SQLite以符合标准(我们将来可能会这样做),但是当发现疏忽时,SQLite的使用范围很广,如果我们解决问题,我们担心会破坏遗留代码.

所以现在我们已经选择在PRIMARY KEY列中继续允许NULL.但是,开发人员应该意识到,我们可能会在未来更改SQLite以符合SQL标准,并应相应地设计新程序.

- SQLite理解的SQL:CREATE TABLE

Erw*_*out 26

假设您有一个包含可空列Kn的主键.

如果你想让第二行被拒绝,那么在第二行中Kn是null并且表已经包含一个Kn null的行,那么你实际上是要求系统将对待比较"row1.Kn = row2 .Kn"赋予TRUE(因为你不知何故希望系统检测到那些行中的键值确实相等).但是,这种比较归结为比较"null = null",并且标准已经明确指定null不比较等于任何东西,包括它自己.

为了满足你的需要,因此SQL会偏离自己关于null处理的原则.SQL中存在无数的不一致,但这个特殊的一个从未超越委员会.

  • "为了满足你想要的东西" - 你回答了我没有问过的事情.我问为什么有些DBMS有,而不是为什么不应该这样做 (5认同)
  • 很抱歉这次晚会很晚,但我偶然发现了这一点.我并不反对你所说的内容,但你可以拥有一个唯一的索引字段,允许空值,并且它不允许多行在字段中包含null.这需要比较(null == null)=> true.事实上,在MS SQL中,您可以忽略比较中的空值,然后您可以在该列中拥有多个具有空值的行. (2认同)

Phi*_*ley 5

就关系数据库理论而言:

  • 表的主键用于唯一标识表中的每一行
  • 列中的NULL值表示您不知道该值是什么
  • 因此,永远不要使用“我不知道”的值来唯一标识表中的行。

根据要建模的数据,可以使用“弥补”值代替NULL。我使用了0,“ N / A”,“ 1980年1月1日”和类似的值来表示虚拟“已知丢失”数据。

大多数(如果不是全部)数据库引擎都允许UNIQUE约束或索引,但确实允许NULL列值,尽管(理想情况下)只可以为一行分配空值(否则它将不是唯一值)。这可以用来支持那些不适用于关系理论的恼人的,务实的(但有时是必要的)情况。

  • 使用远远超出有效值范围的虚假值会影响基数计算,通常是个坏主意。NULL表示NULL,1990年1月1日并不表示NULL。 (2认同)

Ham*_*ite 5

我不知道MySQL的旧版本是否与此不同,但是从现代版本开始,主键必须在非空的列上.请参阅手册页CREATE TABLE:"A PRIMARY KEY是一个唯一索引,其中必须将所有键列定义为NOT NULL.如果未明确NOT NULL声明它们,MySQL会如此隐式地(并且默默地)声明它们."


And*_*yle 3

好吧,它可以让您在数据库中本机实现空对象模式。因此,如果您在代码中使用类似的东西,它与数据库交互非常密切,您可以只查找与键对应的对象,而不必特殊情况进行空检查。

现在,我不确定这是否是有价值的功能,但这确实是一个问题,即在绝对所有情况下禁止空密钥的优点是否超过阻碍某人(无论好坏)实际上想要使用空密钥的缺点。只有当您能够通过保证键非空来证明一些重要的改进(例如更快的键查找)时,这才值得。一些数据库引擎会显示这一点,其他引擎可能不会。如果强迫这样做没有任何真正的好处,为什么要人为地限制你的客户呢?