Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 不递归地更新触发器中的行_Postgresql_Triggers - Fatal编程技术网

Postgresql 不递归地更新触发器中的行

Postgresql 不递归地更新触发器中的行,postgresql,triggers,Postgresql,Triggers,我有两张桌子: CREATE TABLE first ( id text primary key, updated_at timestamp, data text ); CREATE TABLE second ( id text REFERENCES first (id), book_error text, ); 当这些表中的任何一个已经更新时,我需要始终更新第一个表中的updated\u at字段。我写道: CREATE FUNCTION updat

我有两张桌子:

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

CREATE TABLE second (
    id text REFERENCES first (id),
    book_error text,
);
当这些表中的任何一个已经更新时,我需要始终更新第一个表中的
updated\u 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语句导致在执行之前再次调用此触发器。
如何在不再次触发触发器的情况下更新内部触发器?

Per

TG_表_名称

数据类型名称;导致触发器调用的表的名称

使用触发器函数中的变量:

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;

TG_表_名称

数据类型名称;导致触发器调用的表的名称

使用触发器函数中的变量:

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;

pg\u trigger\u 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

pg\u trigger\u 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