为什么SQLite会插入重复的复合主键?

时间:2017-05-07 03:50:05

标签: python sqlite primary-key composite-primary-key

代码:

import sqlite3
c = sqlite3.Connection(':memory:')
c.execute('CREATE TABLE foo(a INTEGER, b VARCHAR(8), PRIMARY KEY(a, b))')
c.execute('INSERT INTO foo(a) VALUES (1)')
c.execute('INSERT INTO foo(a) VALUES (1)')
print(c.execute('SELECT * FROM foo').fetchall())

输出:

[(1, None), (1, None)]

为什么SQLite插入包含重复主键的行?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

SQL PK(PRIMARY KEY)表示UNIQUE NOT NULL。你不应该期望能够在PK的值中使用NULL,更不用说只有一个。您应该声明PK列NOT NULL并且不将NULL放入其中。

SQL As Understood By SQLite

  

具有主键的表中的每一行必须在其主键列中具有唯一的值组合。为了确定主键值的唯一性,NULL值被认为与所有其他值不同,包括其他NULL。如果INSERT或UPDATE语句尝试修改表内容,以便两个或多个行具有相同的主键值,那么就是违反约束。

     

根据SQL标准,PRIMARY KEY应始终表示NOT NULL。不幸的是,由于某些早期版本中的错误,在SQLite中并非如此。除非列是INTEGER PRIMARY KEY或表是WITHOUT ROWID表或列声明为NOT NULL,否则SQLite允许PRIMARY KEY列中的NULL值。可以修复SQLite以符合标准,但这样做可能会破坏遗留应用程序。因此,已决定仅记录SQLite在大多数PRIMARY KEY列中允许NULL的事实。

由于PK中的NULL是针对SQL的,因此在PK中约束和操作具有NULL的表时,SQLite会选择做什么。但它使用通常的SQL解释,即出于UNIQUE的目的,NULL不等于NULL。这就像声明列集UNIQUE NULL时一样。因此,作为约束,SQLite PK是UNIQUE的同义词,而不是UNIQUE NOT NULL。

  

UNIQUE约束类似于PRIMARY KEY约束,但单个表可能具有任意数量的UNIQUE约束。对于表上的每个UNIQUE约束,每行必须包含由UNIQUE约束标识的列中的唯一值组合。出于UNIQUE约束的目的,NULL值被认为与所有其他值不同,包括其他NULL。

答案 1 :(得分:1)

与许多其他SQL数据库一样,SQLite将两个NULL == NULL视为唯一性的不同值(部分原因是,在SQL中,b为false)。

我不相信有办法改变这种行为。作为解决方法,您可以在列{{1}}中使用空字符串作为"没有值"。