PostgreSQL函数因OUT参数报错:返回类型需为record,求修复方案
解决PostgreSQL函数的
function result type must be record because of OUT parameters错误 嘿,这个错误我太熟了!核心问题出在你的函数返回类型声明和OUT参数的使用冲突了:当你在函数里定义了OUT参数时,PostgreSQL会自动把函数的返回类型默认设为这些OUT参数组成的record类型,但你现在却声明函数返回setof ret_cursor,这俩类型根本不兼容,所以就抛出了这个42P13错误。
接下来我分两种最常见的场景给你修正方案,你可以根据自己的实际需求选:
场景1:你其实想直接返回查询结果的行(不是游标)
看你的函数逻辑,大概率是想查询auth_monitor表的那些字段,然后把数据直接返回。那你得改一下返回声明,去掉RETURNS setof ret_cursor,同时简化函数体内的逻辑(不需要搞游标和return next那套):
修改后的函数代码:
CREATE OR REPLACE FUNCTION fun_audit_trail(in as_on_date date, out mail_id varchar, out user_id varchar, out user_name varchar, out last_login_time timestamp, out last_logout_time timestamp, out logout_flag varchar, out user_available_flag varchar) RETURNS SETOF record LANGUAGE plpgsql COST 100.0 SECURITY INVOKER AS $BODY$ BEGIN RETURN QUERY SELECT am.am_usrmailid, am.am_usr_loginid, am.am_usr_name, am.am_last_login_time, am.am_last_logout_time, am.am_logout_flag, am.am_usr_available_flag FROM auth_monitor am WHERE am.am_last_login_time <= as_on_date; END $BODY$;
要是你想让函数的返回结构更清晰(调用的时候不用猜字段),更规范的做法是先定义一个自定义类型,再返回这个类型的集合:
- 先创建自定义类型:
CREATE TYPE audit_trail_result AS ( mail_id varchar, user_id varchar, user_name varchar, last_login_time timestamp, last_logout_time timestamp, logout_flag varchar, user_available_flag varchar );
- 然后修改函数返回这个类型(还能去掉OUT参数,更简洁):
CREATE OR REPLACE FUNCTION fun_audit_trail(as_on_date date) RETURNS SETOF audit_trail_result LANGUAGE plpgsql COST 100.0 SECURITY INVOKER AS $BODY$ BEGIN RETURN QUERY SELECT am.am_usrmailid, am.am_usr_loginid, am.am_usr_name, am.am_last_login_time, am.am_last_logout_time, am.am_logout_flag, am.am_usr_available_flag FROM auth_monitor am WHERE am.am_last_login_time <= as_on_date; END $BODY$;
场景2:你确实需要返回游标(给外部程序处理)
如果你真的是要返回游标(比如让Java、Python这类外部程序去遍历游标),那得把所有OUT参数都去掉,把返回类型声明为refcursor,然后调整函数逻辑:
修改后的函数代码:
CREATE OR REPLACE FUNCTION fun_audit_trail(as_on_date date) RETURNS refcursor LANGUAGE plpgsql COST 100.0 SECURITY INVOKER AS $BODY$ DECLARE ref_cursor refcursor; BEGIN OPEN ref_cursor FOR SELECT am.am_usrmailid, am.am_usr_loginid, am.am_usr_name, am.am_last_login_time, am.am_last_logout_time, am.am_logout_flag, am.am_usr_available_flag FROM auth_monitor am WHERE am.am_last_login_time <= as_on_date; RETURN ref_cursor; END $BODY$;
调用这种返回游标的函数时,得在事务里操作,举个例子:
BEGIN; SELECT fun_audit_trail('2024-01-01'); -- 这里会返回一个游标名称,比如 <unnamed portal 1> FETCH ALL FROM "<unnamed portal 1>"; -- 替换成实际返回的游标名称 COMMIT;
总结一下:先搞清楚自己是要直接返回数据行还是返回游标,然后对应调整函数的返回类型和内部逻辑,就能解决这个冲突问题啦。
内容的提问来源于stack exchange,提问作者abraham




