You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle PL/SQL调用返回REF CURSOR的多记录函数如何处理

你原代码报错的原因是sb_transfer_crse.f_query_all返回的是transfer_crse_ref类型的引用游标,不是单行结果,不能直接用SELECT ... INTO给单组变量赋值,需要先接收游标再处理,以下是两种常见实现方案:

方案1:PL/SQL循环逐条处理

适合需要对每条记录做个性化业务处理的场景,实现代码如下:

DECLARE
  -- 入参变量,填写你要查询的机构编码
  VAR_p_sbgi_code shbtatc.shbtatc_sbgi_code%TYPE := '000497';
  -- 接收函数返回的引用游标
  v_crse_cur transfer_crse_ref;
  -- 存储单条返回记录的变量,和函数返回的record类型完全匹配
  v_crse_rec transfer_crse_rec;
BEGIN
  -- 调用函数获取结果游标
  v_crse_cur := sb_transfer_crse.f_query_all(p_sbgi_code => VAR_p_sbgi_code);
  
  -- 循环遍历游标所有记录
  LOOP
    FETCH v_crse_cur INTO v_crse_rec;
    -- 游标遍历结束时退出循环
    EXIT WHEN v_crse_cur%NOTFOUND;
    
    -- 此处编写单条记录的处理逻辑,示例为打印课程信息
    DBMS_OUTPUT.PUT_LINE('课程编码:' || v_crse_rec.r_subj_code_trns || v_crse_rec.r_crse_numb_trns || ',课程名称:' || v_crse_rec.r_trns_title);
  END LOOP;
  
  -- 关闭游标释放资源
  CLOSE v_crse_cur;
EXCEPTION
  WHEN OTHERS THEN
    -- 异常场景下也需关闭游标避免资源泄漏
    IF v_crse_cur%ISOPEN THEN
      CLOSE v_crse_cur;
    END IF;
    RAISE;
END;
/
方案2:批量导出到新表/临时表

如果不需要逐行处理,直接全量落地数据的话,可按以下步骤操作:

步骤1:创建存储数据的表

可根据需求创建临时表或普通永久表,字段和transfer_crse_rec定义对齐即可,示例:

-- 创建会话级临时表,也可替换为普通CREATE TABLE语句创建永久表
CREATE GLOBAL TEMPORARY TABLE tmp_transfer_crse (
  sbgi_code               shbtatc.shbtatc_sbgi_code%TYPE,
  program                 shbtatc.shbtatc_program%TYPE,
  tlvl_code               shbtatc.shbtatc_tlvl_code%TYPE,
  subj_code_trns          shbtatc.shbtatc_subj_code_trns%TYPE,
  crse_numb_trns          shbtatc.shbtatc_crse_numb_trns%TYPE,
  trns_title              shbtatc.shbtatc_trns_title%TYPE,
  term_code_eff_trns      shbtatc.shbtatc_term_code_eff_trns%TYPE,
  trns_low_hrs            shbtatc.shbtatc_trns_low_hrs%TYPE,
  trns_high_hrs           shbtatc.shbtatc_trns_high_hrs%TYPE
  -- 其余需要存储的字段可参考transfer_crse_rec的定义自行补充
) ON COMMIT PRESERVE ROWS;

步骤2:批量插入数据

方式A:兼容所有Oracle版本的批量插入

性能最优,无版本限制:

DECLARE
  VAR_p_sbgi_code shbtatc.shbtatc_sbgi_code%TYPE := '000497';
  v_crse_cur transfer_crse_ref;
  -- 定义集合类型存储批量读取的结果
  TYPE crse_tab_type IS TABLE OF transfer_crse_rec INDEX BY PLS_INTEGER;
  v_crse_tab crse_tab_type;
BEGIN
  v_crse_cur := sb_transfer_crse.f_query_all(p_sbgi_code => VAR_p_sbgi_code);
  -- 批量读取所有结果到集合,可加LIMIT 1000参数控制单次读取条数
  FETCH v_crse_cur BULK COLLECT INTO v_crse_tab;
  CLOSE v_crse_cur;
  
  -- 批量插入到目标表
  FORALL i IN 1 .. v_crse_tab.COUNT
    INSERT INTO tmp_transfer_crse(
      sbgi_code, program, tlvl_code, subj_code_trns, crse_numb_trns, trns_title, term_code_eff_trns, trns_low_hrs, trns_high_hrs
    ) VALUES (
      v_crse_tab(i).r_sbgi_code, v_crse_tab(i).r_program, v_crse_tab(i).r_tlvl_code, v_crse_tab(i).r_subj_code_trns,
      v_crse_tab(i).r_crse_numb_trns, v_crse_tab(i).r_trns_title, v_crse_tab(i).r_term_code_eff_trns,
      v_crse_tab(i).r_trns_low_hrs, v_crse_tab(i).r_trns_high_hrs
    );
  COMMIT;
END;
/

方式B:Oracle 12c+ 简化写法

如果数据库版本为12c及以上,可直接通过SQL读取游标内容插入,代码更简洁:

INSERT INTO tmp_transfer_crse(
  sbgi_code, program, tlvl_code, subj_code_trns, crse_numb_trns, trns_title
)
SELECT 
  r_sbgi_code, r_program, r_tlvl_code, r_subj_code_trns, r_crse_numb_trns, r_trns_title
FROM TABLE(sb_transfer_crse.f_query_all(p_sbgi_code => '000497'));

提示:如果方式B执行报错提示类型不识别,降级使用方式A即可。

内容的提问来源于stack exchange,提问作者moore1emu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 00:15:05