将TG_TABLE_NAME解释为值以更新其他表中的行

时间:2018-10-18 12:30:36

标签: postgresql triggers plpgsql

每当某些其他表被更新时,我想用最新的时间戳更新master_table_info表中的一行。表中的每一行对应于另一个表。我已经创建了此函数,但是无法将TG_TABLE_NAME解释为变量值而不是新列。因此,我得到了错误column some_table does not exist。如何将其解释为值?

CREATE OR REPLACE FUNCTION master_table_timestamp()
RETURNS TRIGGER AS
$$
BEGIN
    EXECUTE format('
    UPDATE master_table_info
    SET updated_at = NOW()
    WHERE table_name = %I', TG_TABLE_NAME);
    RETURN NULL;
END;
$$
language plpgsql;

CREATE TRIGGER master_table_timestamp
BEFORE UPDATE ON some_table
EXECUTE PROCEDURE master_table_timestamp();

编辑

基于到目前为止的答案/评论并阅读了触发器文档,我意识到我应该使用TG_TABLE_NAME并更改为AFTER触发器。但是,使用触发器修改表不会对master_table_info造成任何更改。怎么了?

CREATE OR REPLACE FUNCTION master_table_timestamp()
RETURNS TRIGGER AS
$$
BEGIN
    UPDATE master_table_info
    SET updated_at = NOW()
    WHERE table_name = TG_TABLE_NAME;
    RETURN new;
END;
$$
language plpgsql;

CREATE TRIGGER master_table_timestamp
AFTER UPDATE ON some_table
EXECUTE PROCEDURE master_table_timestamp();

第二次编辑

此代码在我上面的编辑中(基于答案的帮助)是正确的。我只需要强制手动刷新表即可正确显示它。

1 个答案:

答案 0 :(得分:2)

%I将占位符替换为标识符。因此,生成的SQL将是

UPDATE master_table_info
SET updated_at = NOW()
WHERE table_name = some_table;

要替换文字值,您需要%L作为String中的占位符。 %L占位符负责正确引用值,因此,如果使用该值,则生成的字符串将是:

UPDATE master_table_info
SET updated_at = NOW()
WHERE table_name = 'some_table';

这是您期望的。


但是,不需要动态SQL。在before触发器中使用该函数时,重要的是从该函数返回一个非null值,否则UPDATE语句将被取消。

CREATE OR REPLACE FUNCTION master_table_timestamp()
RETURNS TRIGGER AS
$$
BEGIN
    UPDATE master_table_info
      SET updated_at = NOW()
    WHERE table_name = TG_TABLE_NAME;

    RETURN new; --<< return a NON-NULL value here!
END;
$$
language plpgsql;