【问题标题】:PL/SQL print out ref cursor returned by a stored procedurePL/SQL 打印出存储过程返回的引用游标
【发布时间】:2011-08-14 21:37:17
【问题描述】:

如何从存储过程(OUT 变量)返回的引用游标中获取数据并将结果行打印到 SQL*PLUS 中的 STDOUT?

ORACLE 存储过程:

PROCEDURE GetGrantListByPI(p_firstname IN VARCHAR2, p_lastname IN VARCHAR2,
p_orderby IN VARCHAR2, p_cursor OUT grantcur);

PL/SQL:

SET SERVEROUTPUT ON;

DECLARE
  TYPE r_cursor IS REF CURSOR;
  refCursor r_cursor;

  CURSOR grantCursor IS
    SELECT last_name, first_name
    FROM ten_year_pis
    WHERE year_added = 2010;

  last_name VARCHAR2(100);
  first_name VARCHAR2(100);

BEGIN
  OPEN grantCursor;
  FETCH grantCursor INTO last_name, first_name;

  WHILE grantCursor%FOUND LOOP
    PMAWEB_PKG.GetGrantListByPI(last_name, first_name, 'last_name', refCursor);

    --HOW DO I LOOP THROUGH THE RETURNED REF CURSOR (refCursor)
    --AND PRINT THE RESULTING ROWS TO STDOUT?

    FETCH grantCursor into last_name, first_name;
  END LOOP;
  CLOSE grantCursor;
END;
/

【问题讨论】:

    标签: oracle plsql ref database-cursor


    【解决方案1】:

    注意:此代码未经测试

    为您的 refCursor 返回类型定义一条记录,称为rec。例如:

    TYPE MyRec IS RECORD (col1 VARCHAR2(10), col2 VARCHAR2(20), ...);  --define the record
    rec MyRec;        -- instantiate the record
    

    一旦你从你的过程中返回了 refcursor,你就可以在你的 cmets 所在的位置添加以下代码:

    LOOP
      FETCH refCursor INTO rec;
      EXIT WHEN refCursor%NOTFOUND;
      dbms_output.put_line(rec.col1||','||rec.col2||','||...);
    END LOOP;
    

    【讨论】:

    • 问题是存储过程返回一个引用游标作为两个表之间连接的结果。如何引用连接表的返回类型?
    • 您需要了解光标中的类型和大小才能理解它。使用联接中的字段定义记录,并将行提取到记录中。
    • 感谢@DCookie,但如果我必须从每一行中只读取一列,那么我能做什么。我需要创建整个结构吗?
    • 您必须创建记录类型以镜像您选择的数据。
    • 请注意,您需要在 SQL Developer 中声明的顶部添加此行:SET SERVEROUTPUT ON
    【解决方案2】:

    您可以在 SQLPlus 级别使用绑定变量来执行此操作。当然,您几乎无法控制输出的格式。

    VAR x REFCURSOR;
    EXEC GetGrantListByPI(args, :x);
    PRINT x;
    

    【讨论】:

    • 你知道如何在一个过程中应用同样的逻辑吗?我需要它作为 ETL 工具(Pentaho 数据集成)
    • @YorfrankBastidas 你看过上面的答案了吗 - stackoverflow.com/a/5822771/6568?这讨论了在 PL/SQL 代码中使用 refcursor。
    【解决方案3】:

    如果要打印 select 子句中的所有列,可以使用 autoprint 命令。

    CREATE OR REPLACE PROCEDURE sps_detail_dtest(v_refcur OUT sys_refcursor)
    AS
    BEGIN
      OPEN v_refcur FOR 'select * from dummy_table';
    END;
    
    SET autoprint on;
    
    --calling the procedure
    VAR vcur refcursor;
    DECLARE 
    BEGIN
      sps_detail_dtest(vrefcur=>:vcur);
    END;
    

    希望这能给你一个替代解决方案

    【讨论】:

      【解决方案4】:

      更简单的选择是使用 DBMS_SQL.return_result();

      假设您的包/过程/游标规格如下。

          create or replace PACKAGE my_package IS
          
          TYPE my_ref_cursor_type IS REF CURSOR;
          
          PROCEDURE my_procedure (
              p_in_param1     IN     VARCHAR2, 
              p_in_param2     IN     VARCHAR2, 
              p_in_param3     IN     VARCHAR2, 
              p_my_ref_cursor OUT    my_ref_cursor_type,
              p_err_code      OUT    NUMBER,
              p_err_msg       OUT    VARCHAR2   
              );
          
          END my_package;
      

      尝试从您的 sql 开发人员 WORKSHEET 中调用该过程

      SET SERVEROUTPUT ON;
      
      DECLARE
      
        P_MY_REF_CURSOR my_schema.my_package.my_ref_cursor_type;
        P_ERR_CODE NUMBER;
        P_ERR_MSG VARCHAR2(200);
        
      BEGIN
      
        my_package.my_procedure(
          'VALUE1',
          'VALUE2',
          'VALUE3',
          P_MY_REF_CURSOR => P_MY_REF_CURSOR,
          P_ERR_CODE => P_ERR_CODE,
          P_ERR_MSG => P_ERR_MSG
        );
          DBMS_OUTPUT.PUT_LINE(P_ERR_MSG); 
          DBMS_OUTPUT.PUT_LINE(P_ERR_CODE); 
          DBMS_SQL.return_result(P_MY_REF_CURSOR);
      
      END;
      

      希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-14
        • 1970-01-01
        相关资源
        最近更新 更多