【问题标题】:SQLite Update Execution Order with UNIQUE具有唯一性的 SQLite 更新执行顺序
【发布时间】:2019-06-17 02:49:21
【问题描述】:

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

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

假设数据库包含一系列行,在 bar 列中具有从 1 到 100 的连续整数值,并且它们已按顺序插入。

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

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

SQLite 拒绝执行此更新,说“Error: UNIQUE constraint failed: foo.bar”好吧,当然,如果查询一次执行一行并从满足 WHERE 子句的第一行开始,确实会违反 UNIQUE 约束:两行将有一个值为 23 的 bar 列(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);

【问题讨论】:

  • 我不知道你的问题的答案。在这种情况下,我通常会做的是删除唯一约束,进行更新,然后重新添加约束。
  • 插入临时表,在那里进行更改,从原始表中删除行,然后从临时表中插入?
  • @Ben - 我有这个想法,但看起来 SQLite 不支持删除约束或删除与 UNIQUE 约束相关的索引。 :-(
  • @Shawn - 这是我希望避免的那种复杂的方法。但它可能是唯一适用于这种环境的...
  • @BrianA.Henning 如果将唯一约束设为独立索引而不是表定义的一部分,则很容易删除。

标签: sql sqlite sql-update


【解决方案1】:

如果将唯一约束从表定义中移出到自己的独立索引中是可行的,那么实现 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;

【讨论】:

    【解决方案2】:

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

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

    -- 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 - 更新数据:-

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-10
      • 1970-01-01
      • 2017-11-04
      • 1970-01-01
      • 2022-08-24
      • 2018-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多