http://en.wikipedia.org/wiki/Upsert

在SQL Server上插入更新存储过程

在SQLite中是否有一些我没有想到的聪明的方法来做到这一点?

基本上,如果记录存在,我想要更新四列中的三列, 如果它不存在,我想插入记录的默认值(NUL)为第四列。

ID是一个主键,所以UPSERT只会有一条记录。

(我试图避免选择的开销,以确定我是否需要更新或插入明显)

建议吗?


我无法确认在SQLite网站上创建表的语法。 我还没有构建一个演示来测试它,但它似乎不受支持。

如果是的话,我有三列,所以它实际上是这样的:

CREATE TABLE table1( 
    id INTEGER PRIMARY KEY ON CONFLICT REPLACE, 
    Blob1 BLOB ON CONFLICT REPLACE, 
    Blob2 BLOB ON CONFLICT REPLACE, 
    Blob3 BLOB 
);

但前两个斑点不会引起冲突,只有ID会 所以我假设Blob1和Blob2不会被替换(如期望的那样)


SQLite中绑定数据时的更新是一个完整的事务,也就是说 每个要更新的发送行都需要:Prepare/Bind/Step/Finalize语句 与允许使用重置函数的INSERT不同

语句对象的生命周期是这样的:

使用sqlite3_prepare_v2()创建对象 使用sqlite3_bind_接口将值绑定到主机参数。 通过调用sqlite3_step()运行SQL 使用sqlite3_reset()重置语句,然后返回步骤2并重复。 使用sqlite3_finalize()销毁语句对象。

更新我猜是慢与插入相比,但它如何比较选择使用主键?

也许我应该使用选择读取第4列(Blob3),然后使用REPLACE写一个新记录混合原始的第4列与前3列的新数据?


当前回答

我想这可能就是你想要的:ON冲突条款。

如果你这样定义你的表:

CREATE TABLE table1( 
    id INTEGER PRIMARY KEY ON CONFLICT REPLACE, 
    field1 TEXT 
); 

现在,如果您使用已经存在的id执行INSERT操作,SQLite将自动执行UPDATE而不是INSERT操作。

Hth……

其他回答

这个答案已经更新了,所以下面的评论不再适用。

2018-05-18停止按。

在SQLite中支持UPSERT !UPSERT语法已在3.24.0版本添加到SQLite(待定)!

UPSERT是INSERT的一个特殊语法,如果INSERT违反唯一性约束,它会导致INSERT行为为UPDATE或no-op。UPSERT不是标准SQL。SQLite中的UPSERT遵循PostgreSQL建立的语法。

另外:

另一种完全不同的方法:在我的应用程序中,我将内存中的rowID设置为long。当我在内存中创建行时。(MaxValue永远不会被用作ID,你不会活得足够长....)然后,如果rowID不是那个值,那么它必须已经在数据库中,所以需要一个更新,如果它是MaxValue,那么它需要一个插入。这只有在你可以跟踪应用程序中的rowIDs时才有用。

我想这可能就是你想要的:ON冲突条款。

如果你这样定义你的表:

CREATE TABLE table1( 
    id INTEGER PRIMARY KEY ON CONFLICT REPLACE, 
    field1 TEXT 
); 

现在,如果您使用已经存在的id执行INSERT操作,SQLite将自动执行UPDATE而不是INSERT操作。

Hth……

我所知道的最佳方法是先进行更新,然后进行插入。 “选择的开销”是必要的,但这并不是一个可怕的负担,因为您是在快速的主键上搜索。

你应该能够用你的表和字段名修改下面的语句来做你想做的事情。

--first, update any matches
UPDATE DESTINATION_TABLE DT
SET
  MY_FIELD1 = (
              SELECT MY_FIELD1
              FROM SOURCE_TABLE ST
              WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
              )
 ,MY_FIELD2 = (
              SELECT MY_FIELD2
              FROM SOURCE_TABLE ST
              WHERE ST.PRIMARY_KEY = DT.PRIMARY_KEY
              )
WHERE EXISTS(
            SELECT ST2.PRIMARY_KEY
            FROM
              SOURCE_TABLE ST2
             ,DESTINATION_TABLE DT2
            WHERE ST2.PRIMARY_KEY = DT2.PRIMARY_KEY
            );

--second, insert any non-matches
INSERT INTO DESTINATION_TABLE(
  MY_FIELD1
 ,MY_FIELD2
)
SELECT
  ST.MY_FIELD1
 ,NULL AS MY_FIELD2  --insert NULL into this field
FROM
  SOURCE_TABLE ST
WHERE NOT EXISTS(
                SELECT DT2.PRIMARY_KEY
                FROM DESTINATION_TABLE DT2
                WHERE DT2.PRIMARY_KEY = ST.PRIMARY_KEY
                );

如果你通常做更新,我会..

开始事务 进行更新 检查行数 如果是0,则插入 提交

如果你通常做插入,我会

开始事务 尝试插入 检查主键违反错误 如果出现错误,就进行更新 提交

这样你就避免了选择,你在Sqlite上的事务是健全的。

如果你不介意分两次操作的话。

步骤:

1)使用“插入或忽略”添加新项目

2)使用“Update”更新现有项目

这两个步骤的输入都是相同的新项或可更新项的集合。适用于不需要更改的现有项目。它们将被更新,但使用相同的数据,因此净结果没有变化。

当然,更慢,等等。效率低下。是的。

易于编写sql和维护和理解它?肯定。

这是需要权衡的。 适用于小的上露。对于那些不介意为代码可维护性牺牲效率的人来说非常有用。