PostgreSQL创建触发器提示函数不存在但\df可查的问题求助
问题核心原因
你写的创建触发器的SQL里有两处语法错误,导致函数签名匹配失败:
- 触发器函数参数的引号用错
PostgreSQL中双引号"用于引用标识符(表名、列名、函数名等),单引号'才用于包裹字符串常量。你传递给public.audit_logger的审计表名参数用了双引号包裹,PostgreSQL会把它解析为字段名/标识符,而不是字符串参数,因此会报错找不到对应签名的public.audit_logger()函数。 - 触发器函数的参数逻辑不符合要求
PostgreSQL的触发器函数不能定义显式入参,所有传入的参数都是通过特殊变量TG_ARGV数组在函数内部获取的,如果你定义audit_logger的时候主动写了入参,也会导致签名不匹配。
修复方案
第一步:修改prepare_audit函数中触发器创建的format语句
把原来的双引号替换为单引号,注意因为你在format字符串里要输出单引号,需要用两个单引号转义:
CREATE OR REPLACE FUNCTION prepare_audit() RETURNS void LANGUAGE plpgsql AS $func$ BEGIN DO $$ DECLARE _sql text; BEGIN FOR _sql IN SELECT format('CREATE TABLE IF NOT EXISTS audit.%I_%I(timestamp timestamptz NOT NULL, entity jsonb NOT NULL)' , schemaname , tablename) FROM pg_catalog.pg_tables WHERE schemaname = 'public' LOOP EXECUTE _sql; END LOOP; END $$; DO $$ DECLARE _sql text; BEGIN FOR _sql IN SELECT format('DROP TRIGGER IF EXISTS audittrigger on %I.%I; CREATE TRIGGER audittrigger AFTER INSERT ON %I.%I FOR EACH ROW EXECUTE PROCEDURE public.audit_logger(''audit.%I_%I'')' , schemaname , tablename , schemaname , tablename , schemaname , tablename) FROM pg_catalog.pg_tables WHERE schemaname = 'public' LOOP EXECUTE _sql; END LOOP; END $$; END $func$;
第二步:确认audit_logger函数的定义符合触发器函数要求
触发器函数必须定义为返回trigger类型,且不能声明显式入参,正确的定义结构示例如下:
CREATE OR REPLACE FUNCTION public.audit_logger() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE audit_table_name text := TG_ARGV[0]; -- 取传入的第一个参数,即审计表名 BEGIN -- 此处写你的审计日志插入逻辑,示例如下: EXECUTE format('INSERT INTO %I (timestamp, entity) VALUES (now(), $1)', audit_table_name) USING to_jsonb(NEW); RETURN NEW; END; $$;
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

