Использование триггера SQLite для регистрации значений полей, которые изменяются в обновлении - PullRequest
0 голосов
/ 08 июня 2018

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

CREATE TRIGGER _test7_INSERT AFTER INSERT ON test7 
BEGIN
    INSERT INTO ChangeLog (rid, field, value, tms)
    SELECT *,CAST((julianday('now') - 2440587.5)*86400000  AS INTEGER)
    FROM (VALUES
            (new.rowid, 'field1', new.field1),
            (new.rowid, 'field2', new.field2),
            (new.rowid, 'field3', new.field3)
     ) sub;
END;

Это, очевидно, использует анонимные значения, по которым я не смог найти конкретную документацию, но этоКажется, работает при создании статической таблицы, которую я могу выбрать для вставки в таблицу журнала.

Однако для обновлений я хочу регистрировать только те поля, которые действительно меняются, поэтому, например, если в таблице было 20 полейи только 1 изменилось из-за обновления. Я бы хотел, чтобы в таблицу изменений была добавлена ​​только 1 строка, а не 20. У меня есть триггер, который выглядит следующим образом:

CREATE TRIGGER _test7_UPDATE AFTER UPDATE on test7
BEGIN
    INSERT INTO ChangeLog (rid, field, value, tms)
    SELECT "" AS rid,
           ":1" AS field,
           ":2" AS value,
      CAST((julianday('now') - 2440587.5)*86400000  AS INTEGER) AS tms
    FROM (VALUES
        (old.rowid, 'field1', new.field1, new.field1=old.field1),
        (old.rowid, 'field2', new.field2, new.field2=old.field2),
        (old.rowid, 'field3', new.field3, new.field3=old.field3)
     ) sub
    WHERE ":4"=1;
END;

Но при выполнении операции ничего не вставляетсяОбновить!Если я удаляю дополнительное поле сравнения и удаляю предложение "WHERE", я вижу добавление трех строк, но вместо добавляемых rid, field и value я вижу буквальные значения "", ":1 "и": 2 ".Я не нашел много документации по этим пронумерованным параметрам - на странице языка SQLite в разделе «Параметры» попутно упоминается о них, но очень мало о них говорится - и даже не объясняется, почему": 1" - это на самом деле второй параметр, а "" - первый!Я должен добавить, что я экспериментировал с использованием очень похожего SELECT вне триггера, помещая постоянные значения в таблицу VALUES, и это прекрасно работает!В частности:

SELECT "" AS a, ":1" AS b, ":2" AS c, ":3" AS d
FROM (VALUES
    (11,22,33,44),
    (111,122,133,144),
    (211,222,233,244)
) sub;

возвращает таблицу, содержащую буквенные значения, столбцы, помеченные как «a», «b», «c» и «d».Но та же базовая структура в триггере возвращает буквальные строки с двоеточиями вместо фактических ожидаемых значений.

У меня была яркая идея создать временную таблицу с дополнительным полем, выделить все в нее, затем выбрать все, кромесравнение в реальной таблице журнала.Это не работает, так как CREATE не поддерживается в триггере)

Я также попытался создать ChangeLog, чтобы иметь дополнительное поле для хранения пятого поля в сравнении (например, new.fieldx = old.fieldx), но когда яиспользуйте предложение WHERE, чтобы выбрать только те поля, которые изменились, я возвращаюсь к тому, что ничего не вставляется снова.

Есть ли какой-то другой способ, которым я должен идти об этом, или я делаю что-то не так с тем, как я обращаюсь с позиционными параметрами?

ОБНОВЛЕНИЕ : я былэкспериментировали и обнаружили, что при некоторых обстоятельствах позиционные параметры действительно имеют значения, но они довольно бессмысленные:

DB Fiddle

В частности, поле "" возвращаетзначение параметра second , а поле ":1" возвращает значение параметра четвертого .Зачем?Как мне сослаться на первый и третий параметр?

ОБНОВЛЕНИЕ 2 : После того, как вы поиграете с этим немного больше, кажется, что "", ": 1", ": 2"и т. д. параметры работают нормально, если в таблице VALUES есть только постоянные значения.Любые фактические значения, которые я вставляю, например, из новых, старых и т. Д. - столбцы, которые мне действительно нужны - полностью игнорируются, как будто этих столбцов даже нет!

1 Ответ

0 голосов
/ 08 июня 2018

Это должно сработать:

CREATE TRIGGER _test7_UPDATE AFTER UPDATE on test7
BEGIN
    INSERT INTO ChangeLog (rid, field, value, tms)
    SELECT rowid, field, value, 
        CAST((julianday('now') - 2440587.5)*86400000  AS INTEGER)
        FROM (
        SELECT 0 rowid, '' field, 0 value, 0 keep
        UNION ALL
        SELECT sub.* FROM (VALUES
           (old.rowid, 'field1', new.field1, new.field1!=old.field1),
           (old.rowid, 'field2', new.field2, new.field2!=old.field2),
           (old.rowid, 'field3', new.field3, new.field3!=old.field3)
        ) AS sub
    ) WHERE keep=1;
END

Хитрость заключается в том, чтобы использовать UNION ALL для привязки имен полей из фиктивной строки к последующим постоянным строкам, а затем отфильтровывать фиктивную строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...