当使用SQLite创建一个小应用程序时,我注意到一个奇怪的事情(对我而言)有自动增量列计数器算法行为。
例如,让我们尝试使用以下架构创建数据库
CREATE TABLE numbers (num INTEGER UNIQUE ON CONFLICT IGNORE);
和一个小的Python脚本
import sqlite3
con = sqlite3.connect('db.sqlite3')
cur = con.cursor()
def values():
for i in xrange(1, 3):
yield (i,)
try:
cur.executemany('INSERT INTO numbers (num) VALUES (?)', values())
except sqlite3.DatabaseError, err:
print u'Error: ', err
else:
con.commit()
print u'Number of added rows: %d' % cur.rowcount
cur.close()
con.close()
让我们运行脚本三次。上次使用不同的value()输出,例如xrange(3,5)。所以,我们得到输出
Number of added rows: 2
Number of added rows: 0
Number of added rows: 2
好的,那就让我们检查一下我们的数据库,一切看起来都应该
$ sqlite3 db.sqlite3 'select rowid, * from numbers'
1|1
2|2
3|3
4|4
然后尝试通过向系统rowid列添加自动增量别名来创建数据库。
CREATE TABLE numbers (id INTEGER PRIMARY KEY AUTOINCREMENT, num INTEGER UNIQUE ON CONFLICT IGNORE);
然后执行与上面相同的操作并检查行。
$ sqlite3 db.sqlite3 'select rowid, * from numbers'
1|1|1
2|2|2
5|5|3 <- sqlite jumped over intermediate counter values for rowid and id column
6|6|4
当为表使用IGNORE约束语音分辨算法时,SQLite为rowid和别名自动增量列保存中间计数器值,并在分配新的自动增量值时跳过它们。为什么呢?
答案 0 :(得分:2)
由于:
sqlite发现尚未指定ROWID
并生成一个。对于常规INTEGER PRIMARY KEY
个案,它基本上是MAX(ROWID)+1
。对于INTEGER PRIMARY KEY AUTOINCREMENT
个案例,从特殊sqlite_sequence
表中挑选一个以前从未使用过的新数字。此表包含自动增量行ID的表name
和seq
值。
尝试插入。违反了唯一约束,因此ON CONFLICT IGNORE
分辨率发生。实际上没有做任何事情并且没有引起错误。但是,更改sqlite_sequence
仍然成功,并将在事务完成后提交。