SQLite 使用 UNIQUE 更新执行顺序

问题描述 投票:0回答:3

我正在尝试对我正在更新的列具有唯一约束的表进行批量更新。假设该表定义为:

CREATE TABLE foo (id INTEGER PRIMARY KEY, bar INTEGER UNIQUE);

假设数据库包含一系列行,其

bar
列中的连续整数值范围从 1 到 100,并且它们已按顺序插入。

假设我想在从 17 开始的“bar”序列中放置一个 5 宽的间隙,例如使用如下查询:

UPDATE foo SET bar = bar + 5 WHERE bar > 17;

SQLite 拒绝执行此更新,说“

Error: UNIQUE constraint failed: foo.bar
”好吧,当然,如果查询一次执行一行并从满足 WHERE 子句的第一行开始,确实会违反 UNIQUE 约束:两个rows 将有一个值为 23 的
bar
列(
bar
为 18 的行,以及
bar
为 23 的原始行)。但是,如果我能以某种方式强制 SQLite 自下而上运行更新(从
row
的最高值开始并向后工作),则不会违反 UNIQUE 约束。

SQLite 有一个可选的用于 UPDATE 的 ORDER BY / LIMIT 子句,但这不会影响 UPDATE 发生的顺序;如本页底部所述,“修改行的顺序是任意的。”

是否有一些简单的方法建议 SQLite 按特定顺序处理行更新?或者我是否必须使用更复杂的路线,例如子查询?

更新:这不起作用;出现同样的错误:

UPDATE foo SET bar = bar + 5 WHERE bar IN 
    (SELECT bar FROM foo WHERE bar > 17 ORDER BY bar DESC);
sql sqlite sql-update
3个回答
0
投票

如果将唯一约束从表定义中移出到其自己的独立索引中是可行的,那么实现 Ben 的想法就会变得很容易:

CREATE TABLE foo(id INTEGER PRIMARY KEY, bar INTEGER);
CREATE UNIQUE INDEX bar_idx ON foo(bar);
-- Do stuff
DROP INDEX bar_idx;
-- Update bar values
CREATE UNIQUE INDEX bar_idx ON foo(bar); -- Restore the unique index

如果没有,类似

CREATE TEMP TABLE foo_copy AS SELECT * FROM foo;
 -- Update foo_copy's bar values
DELETE FROM foo;
INSERT INTO foo SELECT * FROM foo_copy;

0
投票

不需要更改表的另一种方法是进行中间更新,将新值设置在现有范围未涵盖的范围内(如果没有值可以为负数,则很容易),然后更新价值观应有的样子。

例如下面使用负中间值演示了这一点:-

-- Load the data
DROP TABLE IF EXISTS foo;
CREATE TABLE foo (id INTEGER PRIMARY KEY, bar INTEGER UNIQUE);
WITH RECURSIVE cte1(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM cte1 LIMIT 100)
    INSERT INTO foo (bar) SELECT * FROM cte1;
-- Show the original data
SELECT * FROM foo;
UPDATE foo SET bar = 0 - (bar + 5) WHERE bar > 17;
UPDATE foo SET bar = 0 - bar WHERE bar < 0;
-- Show the end result
SELECT * FROM foo;

结果 1 - 原始数据

结果 2 - 更新数据:-


0
投票

我也有类似的情况,但就我而言,这是一个排序顺序。 不同之处在于它是一个正整数。 所以我可以分两步更新它。 在你的例子中,它会是这样的:

UPDATE foo SET bar = -(bar + 5) WHERE bar > 17;
UPDATE foo SET bar = - bar      WHERE bar < 0;

或者如果该值存在自然限制或限制:

UPDATE foo SET bar = (bar + 5) + 1000000 WHERE bar > 17;
UPDATE foo SET bar =  bar      - 1000000 WHERE bar > 1000000;

我认为这比删除/重新创建约束或重新创建表更好。

© www.soinside.com 2019 - 2024. All rights reserved.