You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

要是你想让函数的返回结构更清晰(调用的时候不用猜字段),更规范的做法是先定义一个自定义类型,再返回这个类型的集合:

  1. 先创建自定义类型:
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
);
  1. 然后修改函数返回这个类型(还能去掉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

火山引擎 最新活动