【问题标题】:How to check if trigger exists in PostgreSQL?如何检查 PostgreSQL 中是否存在触发器?
【发布时间】:2015-10-16 15:50:23
【问题描述】:

我想验证向某些表添加触发器的数据库迁移的正确性。我正在使用sqitch,所以我想找到一种方法来使用 SQL 查询来检查它。我相信使用 postgres 系统表应该是可能的,但我目前找不到这样做的方法。

【问题讨论】:

    标签: sql database postgresql triggers


    【解决方案1】:

    使用目录pg_trigger

    简单查找表books

    select tgname
    from pg_trigger
    where not tgisinternal
    and tgrelid = 'books'::regclass;
    
        tgname     
    ---------------
     books_trigger
    (1 row)
    

    使用pg_proc获取触发函数的来源:

    select tgname, proname, prosrc 
    from pg_trigger
    join pg_proc p on p.oid = tgfoid
    where not tgisinternal
    and tgrelid = 'books'::regclass;
    
        tgname     |    proname    |                    prosrc
    ---------------+---------------+------------------------------------------------
     books_trigger | books_trigger |                                               +
                   |               | begin                                         +
                   |               |     if tg_op = 'UPDATE' then                  +
                   |               |         if new.listorder > old.listorder then +
                   |               |             update books                      +
                   |               |             set listorder = listorder- 1      +
                   |               |             where listorder <= new.listorder  +
                   |               |             and listorder > old.listorder     +
                   |               |             and id <> new.id;                 +
                   |               |         else                                  +
                   |               |             update books                      +
                   |               |             set listorder = listorder+ 1      +
                   |               |             where listorder >= new.listorder  +
                   |               |             and listorder < old.listorder     +
                   |               |             and id <> new.id;                 +
                   |               |             end if;                           +
                   |               |     else                                      +
                   |               |         update books                          +
                   |               |         set listorder = listorder+ 1          +
                   |               |         where listorder >= new.listorder      +
                   |               |         and id <> new.id;                     +
                   |               |     end if;                                   +
                   |               |     return new;                               +
                   |               | end
    (1 row)
    

    pg_get_triggerdef()函数使用示例:

    select pg_get_triggerdef(t.oid) as "trigger declaration"
    from pg_trigger t
    where not tgisinternal
    and tgrelid = 'books'::regclass;
    
                                                 trigger declaration                
    --------------------------------------------------------------------------------------------------------------
     CREATE TRIGGER books_trigger BEFORE INSERT OR UPDATE ON books FOR EACH ROW EXECUTE PROCEDURE books_trigger()
    (1 row) 
    

    在 Sqitch verify 脚本中,您可以使用匿名代码块,例如:

    do $$
    begin
        perform tgname
        from pg_trigger
        where not tgisinternal
        and tgrelid = 'books'::regclass;
        if not found then 
            raise exception 'trigger not found';
        end if;
    end $$;
    

    【讨论】:

    • 我实际上已经尝试过这个并且很困惑。奇怪的是:我得到 7 个 tgnames 看起来像这样 RI_ConstraintTrigger_c_195564,而不是 1 个。我使用的是 postgresql 9.4。
    • 它们是内部约束触发器。使用 not tgisinternal 跳过它们,就像在编辑后的答案中一样。
    • 此解决方案可能不适用于问题中的 sqitch。我有同样的问题。 Sqitch 需要您的查询返回错误,以便正确验证部署代码。如果触发器不存在,上述解决方案中提到的所有查询只会给出空结果。由于没有抛出错误错误,sqitch 将假定它已正确验证。
    • 根据我对 sqitch 工作原理的了解,它首先运行 deploy 脚本,该脚本将创建添加新触发器。然后它运行verify 脚本来检查触发器是否被正确添加。如果验证脚本运行时没有任何错误,即使deploy 因某种原因失败,它也会假设一切正常。如果verify 脚本会抛出一些错误,sqitch 就会知道某些事情失败了,所以它会运行revert 脚本。
    • @pratpor - 在verify 脚本中使用DO 命令和ASSERTRAISE。查看更新的答案。
    【解决方案2】:

    按触发器名称检查,您可以这样做:

    select trigger_name from information_schema.triggers 
    WHERE trigger_name = 'your_trigger_name'
    

    也可以选择其他信息。

    select event_object_schema as table_schema,
           event_object_table as table_name,
           trigger_schema,
           trigger_name,
           string_agg(event_manipulation, ',') as event,
           action_timing as activation,
           action_condition as condition,
           action_statement as definition
    from information_schema.triggers
    group by 1,2,3,4,6,7,8
    order by table_schema,
             table_name;
    

    栏目详情

    • table_schema - 表架构的名称
    • table_name - 触发器表的名称
    • trigger_schema - 触发器架构的名称
    • trigger_name - 触发器的名称
    • 事件 - 特定的 SQL 操作:插入、更新或删除
    • activation - 触发激活时间:After、Instead of 或 BEFORE
    • 条件 - 触发激活条件
    • 定义 - 触发器的定义 - 在 postgreSQL 中它总是 EXECUTE PROCEDURE function_name()

    如果您不想选择event_manipulation,可以删除查询中的group by

    reference

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 2010-09-12
      • 2017-10-26
      • 1970-01-01
      • 2014-01-07
      • 1970-01-01
      • 2010-09-27
      相关资源
      最近更新 更多