【问题标题】:Insert or update entry but fail on unique constraint violation插入或更新条目但因违反唯一约束而失败
【发布时间】:2020-10-08 16:54:34
【问题描述】:

想象一下这样的表格:

+-----+-------+
| id  | value |
+-----+-------+ 
| id1 | val1  |
| id2 | val2  |
+-----+-------+

idPRIMARY KEY 并且value 具有UNIQUE 约束。

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

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

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

有没有办法用 sqlite 做这样的事情,或者有没有另一种方法来处理这样的情况?

【问题讨论】:

    标签: sqlite


    【解决方案1】:

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

    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 在插入违反 UNIQUE 约束的 value 时导致 sqlite 失败。

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

    举个例子

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

    会导致

    SELECT * FROM test;
    1|update
    

    但使用新的 PK 插入相同的值

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 内置行为似乎是可能的。诀窍是创建表,并像value VARCHAR(32) UNIQUE ON CONFLICT FAIL, PRIMARY KEY(Id) ON CONFLICT REPLACE一样解决各自的冲突,然后只需使用INSERT命令。
      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-01
        • 2011-01-27
        • 1970-01-01
        • 2021-06-28
        相关资源
        最近更新 更多