检查触发器是不是存在
Posted
技术标签:
【中文标题】检查触发器是不是存在【英文标题】:Check if trigger exists检查触发器是否存在 【发布时间】:2016-08-30 13:37:18 【问题描述】:我对公共架构中所有表的触发器有以下查询:
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 );
【问题讨论】:
How to check if trigger exists in PostgreSQL? 【参考方案1】:使用它,您可以检查触发器是否存在,如果不存在则创建它。不要忘记最后一个“;”。
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
$$;
希望对你有帮助。
【讨论】:
【参考方案2】:您可以使用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$;
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
更多解释的相关答案:
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?【讨论】:
@Avon:修复了一个错误:仅循环通过常规表。以上是关于检查触发器是不是存在的主要内容,如果未能解决你的问题,请参考以下文章
检查 SQL Server 中是不是存在触发器的最便携方法是啥?