我正在尝试对要更新的列具有UNIQUE约束的表进行批量更新。假设该表是由以下内容定义的:
CREATE TABLE foo (id INTEGER PRIMARY KEY, bar INTEGER UNIQUE);
假设数据库包含bar
列中一系列具有连续整数值的行,并且它们是顺序插入的。
假设我想在“条”序列中从17开始放置5个宽的间隙,例如使用这样的查询:
UPDATE foo SET bar = bar + 5 WHERE bar > 17;
SQLite拒绝执行此更新,并说“ Error: UNIQUE constraint failed: foo.bar
”。好吧,可以肯定的是,如果一次执行查询并在满足WHERE子句的第一行开始执行查询,则实际上UNIQUE约束将会被违反:两行将有一个bar
列,其值为23(bar
为18的行,而bar
为23的原始行)。但是,如果我能以某种方式强制SQLite自底向上运行更新(从row
的最高值开始并向后工作),则不会违反UNIQUE约束。
SQLite具有用于UPDATE的可选ORDER BY / LIMIT子句,但这并不影响UPDATE发生的顺序;如this page底部所述,“修改行的顺序是任意的。”
是否有一些简单的方法可以建议SQLite按一定顺序处理行更新?还是我必须使用更复杂的路由(例如子查询)?
更新:此操作无效;出现相同的错误:
UPDATE foo SET bar = bar + 5 WHERE bar IN
(SELECT bar FROM foo WHERE bar > 17 ORDER BY bar DESC);
答案 0 :(得分:1)
不需要更改表的另一种方法是进行中间更新,该更新将新值设置为存在的范围内(如果没有值可以为负,则很容易),然后将其设置为将值更新为应有的值。
例如以下使用负中间值演示了这一点:-
-- 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 :(得分: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;