22

我花了一些时间阅读 SQLite文档、Stack Overflow 上的各种问题和答案,以及这件事,但还没有得到完整的答案。

我知道没有办法INSERT OR IGNORE INTO foo VALUES(...)用 SQLite 做类似的事情并取回原始行的 rowid ,最接近它的方法是INSERT OR REPLACE 删除整行并插入新行,从而获得新的 rowid

示例表:

CREATE TABLE foo(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    data TEXT
);

现在我可以这样做:

sql = sqlite3.connect(":memory:")
# create database
sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);", ("Some text.", ))
the_id_of_the_row = None
for row in sql.execute("SELECT id FROM foo WHERE data = ?", ("Some text.", )):
    the_id_of_the_row = row[0]

但理想的东西看起来像:

the_id_of_the_row = sql.execute("INSERT OR IGNORE foo(data) VALUES(?)", ("Some text", )).lastrowid

将行插入表并返回 rowid 的最佳(阅读:最有效)方法是什么,或者如果该行已经存在则忽略该行并仅获取 rowid?效率很重要,因为这会经常发生。

有没有办法INSERT OR IGNORE返回与被忽略行进行比较的行的rowid?这会很棒,因为它和插入一样有效。

4

2 回答 2

17

对我来说最有效的方法是insert or ignore值和selectrowid 在两个单独的步骤中。我unique在列上使用了一个约束data来加速选择并避免重复。

sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);" ("Some text.", ))
last_row_id = sql.execute("SELECT id FROM foo WHERE data = ?;" ("Some text. ", ))

声明并没有我想象的select那么慢。这似乎是由于 SQLite 自动为unique列创建索引。

于 2012-11-14T20:19:53.553 回答
0

INSERT OR IGNORE适用于您不关心记录身份的情况;目标只是拥有一些具有该特定价值的记录。

如果您想知道是否插入了新记录,则必须手动检查:

the_id_of_the_row = None
for row in sql.execute("SELECT id FROM foo WHERE data = ?", ...):
    the_id_of_the_row = row[0]
if the_id_of_the_row is None:
    c = sql.cursor()
    c.execute("INSERT INTO foo(data) VALUES(?)", ...)
    the_id_of_the_row = c.lastrowid

至于效率:当 SQLite 检查data列是否重复时,它必须执行与SELECT您对 .问题。在任何情况下, 需要执行两个单独的INSERT/SELECT查询(按任何顺序,你和我的代码都可以工作,但你的更简单)。

于 2012-11-06T08:14:58.727 回答