嗨,我在SQlite3上遇到了以下问题
我有一张简单的桌子
CREATE TABLE TestTable (id INT, cnt INT);
表中已经有一些行。
我有一些要插入表中的数据:{{id0,cnt0),(id1,cnt1)...}
我想将数据插入表中,如果ID冲突,则更新TestTable.cnt = TestTable.cnt + value.cnt
(values.cnt是cnt0,cnt1 ...基本上是我要插入的数据)
***但是问题是,对id没有主要或唯一的约束,并且不允许更改它!
我目前有什么:
在我的程序中,我遍历所有值
UPDATE TestTABLE SET count = count + value.cnt WHERE id = value.id;
if (sqlite3_changes() == 0)
INSERT INTO MyTable (id, cnt) values (value.id, value.cnt);
但是问题是,对于非常大的数据集,对每个数据条目执行2个查询会花费太长时间。我正在尝试将多个条目捆绑到一个电话中。
如果您对我的描述有疑问,请告诉我,谢谢您的帮助!
答案 0 :(得分:0)
如果能够创建临时表,请执行以下操作。尽管这里没有显示,但我建议将所有这些都包装在事务中。即使您还可以添加临时唯一索引,此技术也可能会提高效率。 (在这种情况下,您可以将UPSERT与临时表中的源数据一起使用。)
CREATE TEMP TABLE data(id INT, cnt INT);
现在,无论是使用主机语言数据库还是编写类似于以下内容的插入语句,都将新数据插入临时表中
INSERT INTO data (id, cnt)
VALUES (1, 100),
(2, 200),
(5, 400),
(7, 500);
现在使用单个UPDATE语句更新所有现有行。 SQLite没有方便的语法来连接表和/或为UPDATE语句提供源查询。但是,可以使用嵌套语句来提供类似的便利:
UPDATE TestTable AS tt
SET cnt = cnt + ifnull((SELECT cnt FROM data WHERE data.id == tt.id), 0)
WHERE tt.id IN (SELECT id FROM data);
请注意,这两个嵌套查询彼此独立。实际上,对于这种简单情况,可以完全消除WHERE子句并获得相同的结果。 WHERE子句只是为了提高效率,仅尝试更新匹配的ID。 SET子句中的另一个子查询也指定了id
上的匹配项,但仅此一项仍将允许更新不匹配的行,默认为null
值并转换为0(通过isnull()
函数)进行无操作。顺便说一下,如果没有isnull()
函数,则总和将导致null并将覆盖非null值。
最后,仅插入不存在id
值的行:
INSERT INTO TestTable (id, cnt)
SELECT data.id, data.cnt
FROM data LEFT JOIN TestTable
ON data.id == TestTable.id
WHERE TestTable.id IS NULL;