Обновить строку в триггере без рекурсии - PullRequest
0 голосов
/ 29 октября 2018

У меня есть две таблицы:

CREATE TABLE first (
    id text primary key,
    updated_at timestamp,
    data text
);

CREATE TABLE second (
    id text REFERENCES first (id),
    book_error text,
);

и мне нужно обновлять поле updated_at в первой таблице всегда, когда обновилась любая из этих таблиц. Я написал это:

CREATE FUNCTION update_timestamp() RETURNS trigger AS $$
    BEGIN
        UPDATE first 
            SET updated_at = current_timestamp
            WHERE id = NEW.id;

        RETURN NEW;
    END;
$$ LANGUAGE plpgsql;

DO $$
DECLARE
    t text;
BEGIN
    FOR t IN 
        SELECT table_name FROM information_schema.tables 
        WHERE table_schema = 'public'
    LOOP
        EXECUTE format('CREATE TRIGGER update_timestamp
                        BEFORE INSERT OR UPDATE ON %I
                        FOR EACH ROW EXECUTE PROCEDURE update_timestamp()',
                        t);
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Но это не работает, потому что оператор update внутри моего триггера снова вызывает этот триггер перед выполнением.
Как я могу обновить внутри триггера, не запуская его снова?

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

С Документация Postgresql ,

pg_trigger_depth() - текущий уровень вложенности триггеров PostgreSQL (0 если не вызывается прямо или косвенно изнутри триггера)

Вы можете использовать это внутри своей функции триггера, чтобы проверить, вызывается ли она изнутри триггера

DO $$
DECLARE
    t text;
BEGIN
    FOR t IN 
        SELECT table_name FROM information_schema.tables 
        WHERE table_schema = 'public'
    LOOP
        EXECUTE format('CREATE TRIGGER update_timestamp
                        BEFORE INSERT OR UPDATE ON %I
                        FOR EACH ROW
                        WHEN (pg_trigger_depth() = 0)
                        EXECUTE PROCEDURE update_timestamp()',
                            t);
        END LOOP;
    END;
    $$ LANGUAGE plpgsql;


test=# Insert into first select 1,now(), 'test';
INSERT 0 1

test=# select * from first;
 id |         updated_at         | data 
----+----------------------------+------
 1  | 2018-10-29 20:18:25.227281 | test
(1 row)

test=# Insert into second select 1, 'test_error';
INSERT 0 1
test=# select * from first;
 id |         updated_at         | data 
----+----------------------------+------
 1  | 2018-10-29 20:19:07.456737 | test
0 голосов
/ 29 октября 2018

за документацию:

TG_TABLE_NAME

Имя типа данных; имя таблицы, вызвавшей вызов триггера.

Использовать переменную в функции триггера:

CREATE OR REPLACE FUNCTION update_timestamp() RETURNS trigger AS $$
BEGIN
    IF TG_TABLE_NAME = 'first' THEN
        NEW.updated_at = current_timestamp;
    ELSE
        UPDATE first 
            SET updated_at = current_timestamp
            WHERE id = NEW.id;          
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...