Подтвердить что ты не робот

Внутреннее соединение 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
4b9b3361

Ответ 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