检查是否存在触发器

时间:2016-08-30 13:37:19

标签: postgresql plpgsql dynamic-sql database-trigger

我对schema public中的所有表都有以下查询:

SELECT 'CREATE TRIGGER ' || tab_name|| '_if_modified_trg INSERT OR UPDATE OR DELETE ON  ' || tab_name|| ' FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ' AS trigger_creation_query
FROM (
   SELECT quote_ident(table_schema) || '.' || quote_ident(table_name) as  tab_name
   FROM information_schema.tables
   WHERE table_schema='public'
   ) AS foo;

我知道如何检查触发器是否存在:

SELECT tgname
from pg_trigger
where not tgisinternal AND tgname='randomname'

但是,如何检查第一个查询是否已存在同名触发器 - 并跳过创建它并继续?这是我的解决方案,但它不起作用:

SELECT 'CREATE TRIGGER ' || tab_name|| '_if_modified_trg INSERT OR UPDATE OR DELETE ON  ' || tab_name|| ' FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ' AS trigger_creation_query
FROM (
   SELECT quote_ident(table_schema) || '.' || quote_ident(table_name) as tab_name
   FROM information_schema.tables
   WHERE table_schema='public'    
 ) AS foo
 WHERE tab_name||'if_modified_trg' NOT IN (
    SELECT tgname
    from pg_trigger
    where not tgisinternal );

2 个答案:

答案 0 :(得分:1)

使用此功能可以检查触发器是否存在,如果不存在则创建它。不要忘记最后一次&#34 ;;"。

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'randomname') THEN
        CREATE TRIGGER randomname  
        AFTER INSERT OR UPDATE OR DELETE ON randomtable
        FOR EACH ROW EXECUTE PROCEDURE randomfunction();
    END IF;
END
$$;

我希望这可以帮到你。

答案 1 :(得分:0)

您可以使用DO语句或plpgsql函数有条件地执行触发器创建:

DO
$do$
BEGIN
   IF EXISTS (
       SELECT 1
       FROM   pg_trigger
       WHERE  NOT tgisinternal AND tgname = 'randomname'
       ) THEN
      -- do nothing
   ELSE
      -- create trigger
   END IF;
END
$do$

仔细检查后,其余代码也会遇到各种问题。 好像你正试图这样做:

DO
$do$
DECLARE
   _tbl regclass;
   _trg text;
BEGIN
   FOR _tbl, _trg IN
      SELECT c.oid::regclass, relname || '_if_modified_trg'
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  n.nspname = 'public'
      AND    c.relkind = 'r'  -- only regular tables
   LOOP
      IF EXISTS (
         SELECT 
         FROM   pg_trigger
         WHERE  tgname  = _trg
         AND    tgrelid = _tbl       -- check only for respective table
         ) THEN
         -- do nothing
      ELSE
         -- create trigger
         EXECUTE format(
            'CREATE TRIGGER %I
             BEFORE INSERT OR UPDATE OR DELETE ON %s
             FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func()'
           , _trg, _tbl::text
         );
      END IF;
   END LOOP;
END
$do$;

出于多种原因,我使用系统目录pg_class而不是information_schema.tables。最重要的是,它包含表格的oid,这使pg_trigger的检查更简单,更不容易出错。

我们实际上可以进一步简化并检查同一查询中是否存在触发器。但速度要快得多:

DO
$do$
DECLARE
   _tbl text;
   _trg text;
BEGIN
FOR _tbl, _trg IN
   SELECT c.oid::regclass::text, relname || '_if_modified_trg'
   FROM   pg_class        c
   JOIN   pg_namespace    n ON n.oid = c.relnamespace
   LEFT   JOIN pg_trigger t ON t.tgname = c.relname || '_if_modified_trg'
                           AND t.tgrelid = c.oid  -- check only respective table
   WHERE  n.nspname = 'public'
   AND    c.relkind = 'r'   -- only regular tables
   AND    t.tgrelid IS NULL -- trigger does not exist yet
LOOP
   EXECUTE format(
      'CREATE TRIGGER %I
       BEFORE INSERT OR UPDATE OR DELETE ON %s
       FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func()'
     , _trg_name, _tbl_oid::text
   );
END LOOP;
END
$do$;

相关答案以及更多解释: