Внутреннее соединение SQLite - обновление с использованием значений из другой таблицы
Это довольно легко и много раз спрашивали, но я не могу заставить его работать.
Я думаю, что SQL-запрос должен работать:
UPDATE table2
SET dst.a = dst.a + src.a,
dst.b = dst.b + src.b,
dst.c = dst.c + src.c,
dst.d = dst.d + src.d,
dst.e = dst.e + src.e
FROM table2 AS dst
INNER JOIN table1 AS src
ON dst.f = src.f
Ответы
Ответ 1
Использование оператора update невозможен, поскольку в sqlite соединения в инструкции обновления не поддерживаются. См. Документы:
инструкция по обновлению
Если вы хотите только обновить один столбец до статического значения, вы можете использовать подзапрос в инструкции обновления правильно. См. Этот пример: Как сделать UPDATE при соединении таблиц в SQLite?
Теперь в вашем примере, сделав предположение, что есть уникальный ключ в "столбце f" - обходное решение/решение, которое я придумал, использует оператор replace:
replace into table2
(a, b, c, d, e, f, g)
select src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f
Я также добавил дополнительный столбец в столбец2 "столбец g", чтобы показать, как вы "обновляете" только некоторые из столбцов этим методом.
Еще одна вещь, которую следует проявлять осторожность, - это использовать "PRAGMA foreign_keys = ON"; это может иметь проблемы с этим, поскольку строка эффективно удаляется и вставлена.
Ответ 2
Я придумал альтернативный метод с использованием TRIGGER и "реверсирование" направления обновления, хотя и ценой фиктивного поля в исходной таблице.
В общих чертах у вас есть таблица Master
и таблица Updates
. Вы хотите обновить некоторые/все поля записей в Master
из соответствующих полей в Updates
, связанных полем ключа Key
.
Вместо UPDATE Master SET ... FROM Master INNER JOIN Updates ON Mater.Key = Updates.Key
вы делаете следующее:
-
Добавьте фиктивное поле TriggerField
в таблицу Updates
, чтобы действовать как фокус запуска.
-
Создайте триггер в этом поле:
CREATE TRIGGER UpdateTrigger AFTER UPDATE OF TriggerField ON Updates
BEGIN
UPDATE Master SET
Field1 = OLD.Field1,
Field2 = OLD.Field2,
...
WHERE Master.Key = OLD.Key
END;
-
Запустите процесс обновления со следующим:
UPDATE Updates SET TriggerField = NULL ;
Примечания
-
Поле фиктивного типа является просто привязкой для триггера, так что любой другой UPDATE Updates SET ...
не будет запускать обновление в Master
. Если вы только INSERT
в Updates
, тогда вам это не понадобится (и при создании триггера можно удалить предложение OF TriggerField
).
-
Из некоторых приблизительных и готовых таймингов это, похоже, работает примерно с той же скоростью, что и REPLACE INTO
, но избегает техники восприятия, слегка неправильного удаления и добавления строк. Это также проще, если вы обновляете только несколько полей в Master
, так как перечисляете только те, которые хотите изменить.
-
Это на порядок быстрее, чем другая альтернатива, которую я видел UPDATE ... FROM
, которая:
UPDATE Master SET
Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
...
;
Обновление шести полей более 1700 записей было примерно 0,05 с для Тони и моих методов, но 2.50s для метода UPDATE ... ( SELECT... )
.
-
AFTER UPDATE
триггеры на Master
, похоже, срабатывают, как ожидалось.
Ответ 3
Как говорит Тони, решение является заменой в пути, но вы можете использовать скрытое поле sqlite rowid, чтобы имитировать полное обновление с помощью соединения вроде:
replace into table2
(rowid,a, b, c, d, e, f, g)
select dest.rowid,src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f
С этим вы воссоздаете полные строки, если у вас нет первичного ключа для замены или стандартного метода для выполнения обновлений с помощью соединений.
Ответ 4
SQLITE не поддерживает UPDATE с INNER JOIN и еще несколько других DB. Внутренние соединения приятны и просты, однако их можно выполнить, используя только UPDATE и выбор подзапроса. Используя предложение where и "IN" с подзапросом и дополнительный подзапрос для "SET", тот же результат всегда можно выполнить. Ниже описано, как это делается.
UPDATE table2
SET a = a + (select a from table1 where table1.f = table2.f),
b = b + (select b from table1 where table1.f = table2.f),
c = c + (select c from table1 where table1.f = table2.f),
d = d + (select d from table1 where table1.f = table2.f),
e = e + (select e from table1 where table1.f = table2.f)
WHERE RowId IN (Select table2.RowId from table1 where table1.f = table2.f)
Ответ 5
Используйте следующий запрос:
UPDATE table2
SET a = Z.a,
b = Z.b,
c = Z.c,
d = Z.d,
e = Z.e
FROM (SELECT dst.id,
dst.a + src.a AS a,
dst.b + src.b AS b,
dst.c + src.c AS c,
dst.d + src.d AS d,
dst.e + src.e AS e
FROM table2 AS dst
INNER JOIN table1 AS src ON dst.f = src.f
)Z
WHERE table2.id = z.id