Обновление строки с помощью триггера без бесконечного цикла

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

Моей первой попыткой было создать триггер, который изменил столбец updated на значение, возвращаемое now(). Но поскольку этот триггер срабатывает при событии обновления, он вызывает бесконечный цикл (обновление обновленного столбца вызывает срабатывание триггера).

Я также попытался реализовать правило, чтобы сделать это с аналогичными эффектами.

Я не могу себе представить, что это то, что я вынужден делать на прикладном уровне, когда когда-либо вызываю и обновляю функцию. Итак, как я могу обновить обновленный столбец этой строки, не вызывая бесконечных циклов?


person user3245442    schedule 12.02.2015    source источник
comment
stackoverflow.com/a/26284695/2101267   -  person Dark Falcon    schedule 12.02.2015
comment
Почему изменение столбца в триггере может вызвать бесконечный цикл? Не понимаю, как new.some_column := now() мог такое сделать.   -  person a_horse_with_no_name    schedule 12.02.2015
comment
Я считаю, потому что триггер срабатывает при обновлении. Итак, при обновлении my_table SET updated = now(); выполняется, он обновляет строку, что затем заставляет триггер обновления снова срабатывать, снова обновлять строку и зацикливаться в этом цикле.   -  person user3245442    schedule 12.02.2015
comment
Ну, вы не должны запускать UPDATE для запускаемой таблицы - и вам это не нужно в первую очередь. Просто присвойте новое значение строке. Смотрите ответ Флимзи. Это действительно единственный правильный способ сделать это.   -  person a_horse_with_no_name    schedule 13.02.2015


Ответы (2)


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

person Tim    schedule 12.02.2015
comment
Без обид, но этот ответ создает у меня впечатление, что вы делаете что-то принципиально неправильное в своем триггере. - person a_horse_with_no_name; 12.02.2015
comment
Без обид. Мой ответ основан на внешнем коде триггера события, а не на sql. Это был единственный способ решить проблему. - person Tim; 13.02.2015

Используйте такой триггер:

CREATE OR REPLACE FUNCTION update() RETURNS trigger AS $$
BEGIN
    IF NEW.updated = OLD.updated THEN
        NEW.updated = NOW()
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER table_update
BEFORE UPDATE ON table
FOR EACH ROW EXECUTE PROCEDURE update()

Таким образом, вы не находитесь в цикле — вы обновляете значение только один раз (до выполнения UPDATE), и вы также не затираете значение, если по какой-то причине вы хотите установить updated явно (как при импорте старые данные из резервной копии, например).

person Flimzy    schedule 12.02.2015