SQLite inner join-обновление с использованием значений из другой таблицы

Это довольно легко и был задан несколько раз, но я не могу заставить его работать. 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

5 ответов


использование инструкции update невозможно, поскольку в SQLite соединения в инструкции update не поддерживаются. См Docs: инструкции Update

Если вы хотите обновить только один столбец до статического значения, вы можете правильно использовать подзапрос в инструкции 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

Я также добавил дополнительный столбец в table2 "столбец g", чтобы показать, как вы" обновите " только некоторые столбцы с помощью этого метода.

еще одна вещь, о которой нужно быть осторожным, - это если вы используете "PRAGMA foreign_keys = ON;" можно иметь проблемы с этим, поскольку строка эффективно удаляется и вставляется.


я придумал альтернативную технику с использованием триггера и" реверсирования " направления обновления, хотя и за счет фиктивного поля в исходной таблице.

в общих чертах, у вас есть Master и Updates таблица. Вы хотите обновить несколько полей в Master из соответствующих полей Updates связанный ключевым полем Key.

вместо UPDATE Master SET ... FROM Master INNER JOIN Updates ON Mater.Key = Updates.Key выполнить следующее:

  1. добавить манекен поле TriggerField до Updates таблица, чтобы действовать в качестве фокуса триггера.

  2. создайте триггер в этом поле:

    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;
    
  3. запустите процесс обновления следующим образом:

    UPDATE Updates SET TriggerField = NULL ;
    

Примечания

  1. фиктивное поле-это просто якорь для триггера, так что любой другой UPDATE Updates SET ... не будет запускать обновление в Master. Если вы только когда-нибудь INSERT на Updates затем вы не нужно (и может удалить OF TriggerField предложение при создании триггера).

  2. из некоторых грубых и готовых таймингов это, похоже, работает примерно с той же скоростью, что и REPLACE INTO но избегает по ощущениям-чуть-не так техника удаления и добавления строк. Это также проще, если вы обновляете только несколько полей в Master как вы только список тех, которые вы хотите изменить.

  3. это на порядки быстрее, чем другие альтернатива, которую я видел 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 s для Тони и моих методов, но 2.50 s на UPDATE ... ( SELECT... ) метод.

  4. AFTER UPDATE триггеры Master кажется, огонь, как и ожидалось.


Как говорит Тони, решением является заменить на путь, но вы можете использовать скрытое поле sqlite rowid для имитации полного обновления с помощью join like:

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

С этим вы воссоздаете полные строки, Если у вас нет первичного ключа для замены или стандартного метода для обновления с помощью соединений.


SQLITE не поддерживает обновление с внутренним соединением, а также несколько других БД. Внутренние соединения хороши и просты, однако это может быть достигнуто с помощью только обновления и выбора подзапроса. Используя предложение 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) 

использовать ниже запроса:

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