首页 文章

在存在UNIQUE约束的情况下模拟UPSERT

提问于
浏览
1

模拟UPSERT之前已经是discusssed . 在我的情况下,我有PRIMARY KEY和额外的UNIQUE约束,我想要关于主键的upsert语义 - 如果存在,则替换现有行,同时检查唯一约束 .

这是使用insert-or-replace的尝试:

drop table if exists test;
create table test (id INTEGER, name TEXT, s INTEGER, 
                   PRIMARY KEY (id, s), 
                   UNIQUE (name, s));

insert or replace into test values (1, "a", 0);
insert or replace into test values (1, "a", 0);
insert or replace into test values (2, "b", 0);
insert or replace into test values (2, "a", 0);

最后一个语句将替换两行 . 这是'插入或替换'的记录行为,但不是我想要的 .

以下是“关于冲突替换”的尝试:

drop table if exists test;
create table test (id INTEGER, name TEXT, s INTEGER, 
                   PRIMARY KEY (id, s) on conflict replace, 
                   UNIQUE (name, s));

insert into test values (1, "a", 0);
insert into test values (1, "a", 0);

我马上得到“UNIQUE约束失败” . 如果不在主键和唯一约束之间共享列,则问题将消失:

drop table if exists test;
create table test (id INTEGER, name TEXT,
                   PRIMARY KEY (id) on conflict replace, 
                   UNIQUE (name));

insert into test values (1, "a");
insert into test values (1, "a");
insert into test values (2, "b");
insert into test values (2, "a");

在这里,我在最后一个语句中得到了约束违规,这是完全正确的 . 遗憾的是,我确实需要在约束之间共享一列 .

这是我对SQL或SQLite问题不了解的问题,以及如何获得所需的效果,除了首先尝试插入然后在失败时进行更新?

2 回答

  • 0

    您是否可以尝试将ON CONFLICT REPLACE子句应用于UNIQUE约束?

    create table test (id INTEGER, name TEXT,
                   PRIMARY KEY (id) on conflict replace, 
                   UNIQUE (name) on conflict replace);
    
  • 0

    SQLite是一个没有客户端/服务器通信开销的嵌入式数据库,因此没有必要尝试在单个语句中执行此操作 .

    要模拟UPSERT,只需单独执行UPDATE / INSERT语句:

    c.execute("UPDATE test SET s = ? WHERE id = ? AND name = ?", [0, 1, "a"])
    if c.rowcount == 0:
        c.execute("INSERT INTO test(s, id, name) VALUES (?, ?, ?)", [0, 1, "a"])
    

相关问题