【问题标题】:UPSERT in SQLiteSQLite 中的 UPSERT
【发布时间】:2013-12-17 20:36:35
【问题描述】:

我不想使用REPLACE INTO,因为它基本上是DELETEINSERT,而且使用旧列中的数据很复杂。

INSERT OR IGNORE 有点小技巧,因为所有错误都会被忽略,所以这不是一个选项。

我读过blog article,它使用以下内容:

UPDATE Table1 SET (...) WHERE Column1='SomeValue'
IF @@ROWCOUNT=0
    INSERT INTO Table1 VALUES (...)

我非常喜欢这种方法,但我不知道如何在 SQLite 中用@@ROWCOUNT 实现这个IF-clause,这就是我得到的:

SELECT CASE (SELECT
    CASE
        WHEN EXISTS(SELECT 1 FROM t WHERE id=2)
            THEN 1
            ELSE 0
    END)
WHEN 1
  UPDATE t set a='pdf' WHERE id=2;
ELSE
  INSERT INTO t (a) VALUES ('pdf');
END

SELECT CASE 似乎是在 SQLite 中使用CASE-clause 的唯一方法,因为其他所有内容都会引发语法错误。但是也不能在SELECT CASE 中使用UPDATE- 或INSERT- 语句,所以这会引发错误。

我尝试了以下方法

UPDATE t set a='pdf' WHERE id=2;
CASE WHEN (changes()=0) THEN
    INSERT INTO t (a) VALUES ('pdf');
END

但这不起作用,因为CASE-clause 会引发语法错误。

谁能提供一个在 SQLite 中使用 @@ROWCOUNT 进行 UPSERT 的示例?

【问题讨论】:

  • @@ROWCOUNT 是 SQLite 中没有的 T-SQL 功能,SQLite 也没有您尝试使用的 IF 或 CASE 语句。如果您确实需要 UPSERT,您可能需要接受“这很复杂”,并使用 solution given in question 418898 或从应用程序代码中检查 SELECT changes() 的结果并基于此执行 INSERT。
  • @@ROWCOUNT 是从我参考的那篇博客文章中借来的,表达不好见谅。我喜欢SELECT changes() 的想法,谢谢

标签: sql sqlite upsert


【解决方案1】:

SQLite 没有内置的类似 UPSERT 的语句,不会删除旧记录。

您应该检查程序中的更改次数,并有条件地执行 INSERT。

但是,如果您真的想在 SQL 中执行此操作,这是可能的;但您必须使用INSERT ... SELECT ... 表单,以便在需要时插入零记录:

BEGIN;
UPDATE t SET a = 'pdf' WHERE id = 2;
INSERT INTO t(id, a) SELECT 2, 'pdf' WHERE changes() = 0;
COMMIT;

【讨论】:

  • 那么为什么大家都在使用REPLACE INTOINSERT OR IGNORE?这个解决方案就像一个魅力,看起来很漂亮,谢谢!
  • INSERT OR IGNORE 正在使用,因为它使用单个 SQL 语句。
  • 如果另一个线程正在更新一行并且在两个查询语句之间更改了 changes() 怎么办?
  • @alizx 使用事务时,其他线程不能干涉。
  • @alizx 连接和事务之间存在 1:1 的关系。如果您想要单独的事务,则需要单独的连接。
【解决方案2】:

在这种情况下,您应该使用 sqlite API 并在您的应用程序中编写“IF 逻辑”。

sqlite3_prepare16_v2(stmt1, "UPDATE t SET a=? WHERE id=?");

sqlite3_prepare16_v2(stmt2, "INSERT INTO t(id, a) VALUES(?, ?)");

for(...) // iterate by rows to be updated/inserted
{
    //set parameter values for stmt1

    sqlite3_step(stmt1);
    if( !sqlite3_changes(dbh) )
    {
        //set parameter values for stmt2
        sqlite3_step(stmt2);
    }
}

【讨论】:

    猜你喜欢
    • 2010-09-29
    • 2021-09-22
    • 2013-02-23
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多