使用ON CONFLICT IGNORE子句的SQLite AUTOINCREMENT列计数器行为

时间:2013-12-13 05:39:08

标签: python sql sqlite

当使用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和别名自动增量列保存中间计数器值,并在分配新的自动增量值时跳过它们。为什么呢?

1 个答案:

答案 0 :(得分:2)

由于:

  1. sqlite发现尚未指定ROWID并生成一个。对于常规INTEGER PRIMARY KEY个案,它基本上是MAX(ROWID)+1。对于INTEGER PRIMARY KEY AUTOINCREMENT个案例,从特殊sqlite_sequence表中挑选一个以前从未使用过的新数字。此表包含自动增量行ID的表nameseq值。

  2. 尝试插入。违反了唯一约束,因此ON CONFLICT IGNORE分辨率发生。实际上没有做任何事情并且没有引起错误。但是,更改sqlite_sequence仍然成功,并将在事务完成后提交。

  3. 参考:http://www.sqlite.org/autoinc.html