【问题标题】:INSERT OR REPLACE multiple rows, but there is no unique or primary keysINSERT OR REPLACE 多行,但没有唯一键或主键
【发布时间】:2019-11-19 19:00:24
【问题描述】:

您好,我在 SQlite3 上遇到了以下问题

我有一张简单的桌子

CREATE TABLE TestTable (id INT, cnt INT);

表中已有一些行。

我有一些数据要插入到表中:{(id0, cnt0), (id1, cnt1)...}

我想往表中插入数据,id冲突,更新TestTable.cnt = TestTable.cnt + value.cnt

(values.cnt是cnt0,cnt1 ...基本上是我要插入的数据)

*** 但是问题是,id没有primary或​​者unique约束,我是不允许改的!

我目前拥有的:

在我的程序中,我遍历所有值

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 次查询需要太长时间。我正在尝试将多个条目捆绑到一个调用中。

如果您对我的描述有任何疑问,请告诉我,谢谢您的帮助!

【问题讨论】:

  • 在列上创建一个临时唯一索引。
  • 请详细说明“不允许更改”,因为这肯定会限制优化流程的可能解决方案。不允许执行任何 DDL 语句吗?您是否允许创建正式的临时表(使用 TEMPORARY 关键字)?因为 sqlite 没有“临时索引”,Shawn 的建议需要实际添加,然后删除索引......这会与您的限制相矛盾吗?

标签: sql database sqlite rdbms


【解决方案1】:

如果您能够创建临时表,请执行以下操作。虽然我没有在这里展示它,但我建议将所有这些包装在一个事务中。即使您还能够添加临时唯一索引,这种技术也可能会提高效率。 (在这种情况下,您可以将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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多