SQLite 插入或替换的奇怪行为

Weird behavior with SQLite insert or replace

我正在尝试增加 SQLite 数据库中某行的计数(如果该行存在),或者添加一个新行(如果它不存在),就像在此 [=12] 中所做的那样=] post。但是,当我尝试快速连续多次执行此 SQL 过程时,我遇到了一些奇怪的行为。作为示例,我尝试了 运行 此代码:

db = connect_to_db()
c = db.cursor()
for i in range(10):
    c.execute("INSERT OR REPLACE INTO subject_words (subject, word, count) VALUES ('subject', 'word', COALESCE((SELECT count + 1 FROM subject_words WHERE subject = 'subject' AND word = 'word'), 1));")
    db.commit()
db.close()

并将以下内容插入数据库

sqlite> select * from subject_words;
subject|word|1
subject|word|2
subject|word|2
subject|word|2
subject|word|2
subject|word|2
subject|word|2
subject|word|2
subject|word|2
subject|word|2

总共有 19 个单词 'word' 和主题 'subject' 的条目。谁能解释一下这种奇怪的行为?

我认为您不了解 INSERT OR REPLACE 的实际作用。 REPLACE 子句只有在不可能进行插入时才会发挥作用,因为违反了唯一约束。例如,如果您的 subject 列是主键。

但是,在没有任何主键或其他约束的情况下,插入具有相同主题的多行并不会违反任何规定;所以没有理由调用 REPLACE 子句。

如果您使用两个 SQL 语句来完成该操作,则该操作更容易编写和理解:

c.execute("""UPDATE subject_words SET count = count + 1
             WHERE subject = ? AND WORD = ?""",
          ['subject', 'word'])
if c.rowcount == 0:
    c.execute("INSERT INTO subject_words (subject, word, count) VALUES (?,?,?)",
              ['subject', 'word', 1])

这不需要对要检查的列使用 UNIQUE 约束,而且效率丝毫不减。