【问题标题】:Simulating UPSERT in presence of UNIQUE constraints在存在 UNIQUE 约束的情况下模拟 UPSERT
【发布时间】:2015-12-23 05:22:46
【问题描述】:

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

这是使用插入或替换的尝试:

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 问题的不理解吗?除了首先尝试插入然后在失败时进行更新之外,我如何获得预期的效果?

【问题讨论】:

    标签: sql sqlite


    【解决方案1】:

    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"])
    

    从 SQLite 3.24.0 开始,您可以使用UPSERT

    【讨论】:

    • 明白了,这就是我现在拥有的代码,它可以完成工作。尽管如此,两个语句的开销还是比一个多,而且不是一种优雅的方法。
    • 如果您使用子选择插入,则不是一个选项
    【解决方案2】:

    您能否尝试将 ON CONFLICT REPLACE 子句也应用于 UNIQUE 约束?

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

    【讨论】:

    • 我认为这相当于我的第一次尝试,因为“插入或替换”基本上是在每个约束上添加替换行为。当我尝试这个建议时,连同上面第一个示例中的数据以及仅“插入”的数据,我都替换了现有的行。
    猜你喜欢
    • 2023-03-12
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    相关资源
    最近更新 更多