Check if trigger exists

ⅰ亾dé卋堺 提交于 2019-12-10 18:37:02

问题


I have the following query to triggers on all tables in 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;

And I know how to check if a trigger exists:

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

But how can I check in the first query whether a trigger with the same name already exists - and skip creating it and just continue? Here is my solution but it doesn't work:

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 );

回答1:


Using this you can check if the trigger exists and create it if not. Don't forget the last ";".

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
$$;

I hope this can help you.




回答2:


You can use a DO statement or a plpgsql function to execute the trigger creation conditionally:

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$

On closer inspection, the rest of your code also has various problems. Seems like you are trying to do this:

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$;

I use the system catalog pg_class instead of information_schema.tables for multiple reasons. Most importantly, it includes the oid of the table, which makes the check on pg_trigger simpler and less error-prone.

We can actually simplify further and check for existence of the trigger in the same query. Substantially faster, yet:

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$;
  • How to check if a table exists in a given schema
  • Information schema vs. system catalogs
  • Select rows which are not present in other table

Related answers with more explanation:

  • EXECUTE of SELECT ... INTO is not implemented
  • Loop on tables with PL/pgSQL in Postgres 9.0+
  • Postgres: check disk space taken by materialized view?


来源:https://stackoverflow.com/questions/39229079/check-if-trigger-exists

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!