关于 sqlite:插入或更新条目但因违反唯一约束而失败

Insert or update entry but fail on unique constraint violation

想象一下这样的表格:

1
2
3
4
5
6
+-----+-------+
| id  | value |
+-----+-------+
| id1 | val1  |
| id2 | val2  |
+-----+-------+

idPRIMARY KEY 并且 value 具有 UNIQUE 约束。

我想要做的是使用一个查询,该查询根据其主键插入或更新条目,但如果违反唯一约束则失败。

例如,如果我尝试插入 id1, val2,我希望查询失败,而插入 id1, val3 应该更新第一行。

我在 sqlite3 中观察到的是,如果我使用 INSERT OR REPLACE 插入 id1, val2 它将替换两个现有条目。我还查看了 sqlite 的 ON CONFLICT 子句,但似乎没有办法区分 UNIQUEPRIMARY KEY 约束违规。

有没有办法用 sqlite 做这样的事情,或者有没有其他方法可以处理这样的情况?


您可以通过如下创建表来实现:

1
2
3
4
5
CREATE TABLE test (
   id INTEGER,
   value VARCHAR(32) UNIQUE ON CONFLICT FAIL,
   PRIMARY KEY(Id) ON CONFLICT REPLACE
);

关键是为不同的列定义不同的ON CONFLICT子句。 PRIMARY KEY(Id) ON CONFLICT REPLACE 将导致 sqlite 在插入具有冲突 PK 的新记录时替换记录,而 value VARCHAR(32) UNIQUE ON CONFLICT FAIL 会导致 sqlite 在插入违反 UNIQUE 约束的 value 时失败。

这将在插入具有相同主键的新记录时更新现有值,但如果您尝试插入具有不同主键和相同值的两条记录,则会失败。

举个例子

1
2
INSERT INTO test VALUES (1,"test");
INSERT INTO test VALUES (1,"update");

将导致

1
2
SELECT * FROM test;
1|update

但使用新的 PK

插入相同的值

1
INSERT INTO test VALUES (2,"update");

将导致 Error: UNIQUE constraint failed: test.value.


OR REPLACE 子句使用任何唯一约束(包括主键约束)来检测冲突。

如果内置的行为不是你想要的,你必须自己做:

1
2
3
c.execute("UPDATE MyTable SET val = ? WHERE id = ?;", [newValue, id])
if c.rowcount == 0:
    c.execute("INSERT INTO MyTable(val, id) VALUES (?, ?);", [newValue, id])


Jan,希望对你有所帮助:https://www.sqlite.org/lang_conflict.html