模式中所有表的PL / PGSQL动态触发器

时间:2018-12-14 02:22:54

标签: sql arrays postgresql triggers psql

我正在寻找通过update_at列的自动更新来自动化每个表更新。我可以使用触发器使此工作适用于特定的表。但是我的主要目标(在任何地方都找不到)是创建一个功能,该功能可动态获取模式中的所有表,并创建相同的触发器,并且仅更改触发器所引用的表名。对于我的一生,我无法弄清楚。

我相信这不应该像我在架构中创建表时那样棘手,因为表名将具有与'updated_at'完全相同的列名。

我尝试并认为可行的一种解决方案是将表架构转换为数组,并对其进行迭代以在每次迭代中调用/创建触发器。但是我没有大量的psql经验,所以我发现自己搜寻了几个小时才能解决这一小问题。

SELECT ARRAY (
            SELECT
                table_name::text
            FROM 
                information_schema.tables

            WHERE table_schema = 'public') as tables;

我也尝试过:

DO $$
DECLARE
    t text;
BEGIN
    FOR t IN 
        SELECT table_name FROM information_schema.columns
        WHERE column_name = 'updated_at'    
    LOOP 
        EXECUTE format('CREATE TRIGGER update_updatedAt
                        BEFORE UPDATE ON %I
                        FOR EACH ROW EXECUTE PROCEDURE updated_at()',
                        t);
    END loop;
    END;
    $$ language 'plpgsql';

程序:

CREATE OR REPLACE FUNCTION updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = now();
    RETURN NEW;
END;
$$ language 'plpgsql';

1 个答案:

答案 0 :(得分:3)

您的DO块有效。唯一的问题是我们不能为多个触发器使用相同的触发器名称。因此,您可以为触发器名称添加一个table_name后缀/前缀。

DO $$
DECLARE
    t text;
BEGIN
    FOR t IN 
        SELECT  table_name FROM information_schema.columns
             WHERE column_name = 'updated_at'    
    LOOP 


        EXECUTE format('CREATE TRIGGER update_updatedAt_%I
                        BEFORE UPDATE ON %I
                        FOR EACH ROW EXECUTE PROCEDURE updated_at()',
                        t,t);
    END loop;
    END;
$$ language 'plpgsql';

另外,为了安全起见,您可以添加检查以查看触发器是否已经存在于information_schema.triggers中。

IF NOT EXISTS ( SELECT 1 from information_schema.triggers 
                     where trigger_name = 'update_updatedat_'|| t)                                                                                      
  THEN
相关问题