Порядок выполнения обновления SQLite с УНИКАЛЬНЫМ - PullRequest
0 голосов
/ 17 июня 2019

Я пытаюсь выполнить массовое обновление таблицы, в которой есть уникальное ограничение для столбца, который я обновляю. Предположим, что таблица определяется как:

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

Предположим, что база данных содержит ряд строк с непрерывными целочисленными значениями в столбце bar в диапазоне от 1 до 100, и что они были вставлены последовательно.

Предположим, я хочу вставить разрыв шириной в пять в последовательность "bar", начинающуюся с 17, например, с помощью такого запроса:

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 имеет необязательное условие ORDER BY / LIMIT для UPDATE, но это не влияет на порядок, в котором происходят UPDATE; как указано в нижней части этой страницы , «порядок, в котором изменяются строки, является произвольным».

Есть ли какой-нибудь простой способ предложить SQLite обрабатывать обновления строк в определенном порядке? Или мне нужно использовать более сложный маршрут, такой как подзапрос?

ОБНОВЛЕНИЕ: Это не работает; появляется та же ошибка:

UPDATE foo SET bar = bar + 5 WHERE bar IN 
    (SELECT bar FROM foo WHERE bar > 17 ORDER BY bar DESC);

Ответы [ 2 ]

1 голос
/ 17 июня 2019

Альтернативой, которая не требует изменения таблицы, является промежуточное обновление, которое устанавливает новые значения в диапазоне, не охватываемом диапазоном (легко, если никакие значения не могут быть отрицательными), который существует и затемобновите значения до того, что они должны быть.

например, следующее демонстрирует это с использованием отрицательных промежуточных значений: -

-- 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 - Исходные данные

enter image description here

Результат 2 - Обновлены данные: -

enter image description here

0 голосов
/ 17 июня 2019

Если выполнимо перемещение уникального ограничения из определения таблицы в его собственный независимый индекс, реализация идеи Бена становится простой:

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...