【问题标题】:SQLite AUTOINCREMENT column counter behavior with ON CONFLICT IGNORE clause带有 ON CONFLICT IGNORE 子句的 SQLite AUTOINCREMENT 列计数器行为
【发布时间】:2013-12-13 05:39:08
【问题描述】:

在使用 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()

让我们运行 3 次脚本。上次使用不同的 values() 输出,例如 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 和别名自动增量列的中间计数器值,并在分配新的自动增量值时跳过它们。为什么?

【问题讨论】:

    标签: python sql sqlite


    【解决方案1】:

    因为:

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

    2. 尝试插入。违反了唯一约束,因此发生ON CONFLICT IGNORE 解析。实际上什么也没做,也没有引发错误。但是,更改 sqlite_sequence 仍然成功,并将在事务完成后提交。

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

    【讨论】:

      猜你喜欢
      • 2017-11-18
      • 2020-06-02
      • 1970-01-01
      • 2015-06-08
      • 2021-11-07
      • 2020-12-07
      • 2016-05-11
      • 2021-03-05
      • 1970-01-01
      相关资源
      最近更新 更多