PostgreSQL触发器函数使用TG_TABLE_NAME查询报错及解决尝试
解决PL/pgSQL触发器动态表查询与字段更新问题
正确的触发器函数实现
CREATE OR REPLACE FUNCTION public.update_volume_usd() RETURNS trigger LANGUAGE 'plpgsql' COST 100 VOLATILE NOT LEAKPROOF AS $BODY$ DECLARE prev_record RECORD; -- 用通用RECORD类型适配多张表 BEGIN -- 动态SQL查询,将结果存入prev_record EXECUTE format(' SELECT * FROM ONLY %I WHERE base = $1 AND quote = ''USDT'' ORDER BY timestamp DESC LIMIT 1 ', TG_TABLE_NAME) INTO prev_record -- INTO放在EXECUTE外部接收动态查询结果 USING NEW.quote; -- 判断是否查询到有效记录 IF prev_record IS NOT NULL THEN NEW.volume_usd := NEW.volume * prev_record.close; END IF; RETURN NEW; END; $BODY$;
错误原因解析
1. 直接使用TG_TABLE_NAME作为表名
TG_TABLE_NAME是PL/pgSQL内置变量,不能直接写在静态SQL的FROM子句中,PostgreSQL会将其识别为字面量表名"tg_table_name",导致找不到对应关系表。必须通过format()函数结合%I占位符(安全转义标识符)生成动态SQL,再用EXECUTE执行。
2. EXECUTE语句的SELECT INTO写法错误
PL/pgSQL不支持在EXECUTE的SQL字符串中写SELECT ... INTO,正确写法是将INTO 变量放在EXECUTE语句末尾,用于接收动态查询的结果集。
3. 固定行类型无法适配多张表
原代码中prev_record daily_data%ROWTYPE限定变量只能接收daily_data表的行结构,无法适配其他表。改用通用RECORD类型后,变量可接收任意表的行数据,满足多表适配需求。
4. 判断记录存在的语法错误
IF EXISTS prev_record是无效语法,正确判断方式是检查RECORD变量是否不为空(IF prev_record IS NOT NULL),也可使用PL/pgSQL内置的FOUND变量(EXECUTE执行查询后,找到记录则FOUND为true),示例:
IF FOUND THEN NEW.volume_usd := NEW.volume * prev_record.close; END IF;
内容的提问来源于stack exchange,提问作者XotEmBotZ
相关产品推荐
相关产品推荐

