在SQLite中的UPSERT

时间:2013-12-02 07:45:13

标签: sql sqlite upsert

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

INSERT OR IGNORE有点像黑客,因为所有错误都被忽略了,所以这不是一个选项。

我读过使用以下内容的blog article

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

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

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的唯一方法,因为其他一切都会引发语法错误。但是也无法在UPDATE中使用INSERT - 或SELECT CASE - 语句,因此会引发错误。

我尝试了以下

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

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

有人可以使用@@ROWCOUNT为SQLite中的UPSERT提供示例吗?

2 个答案:

答案 0 :(得分:11)

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;

答案 1 :(得分:2)

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

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);
    }
}