【问题标题】:How do you get nicely formatted results from an Oracle procedure that returns a reference cursor?如何从返回引用游标的 Oracle 过程中获得格式良好的结果?
【发布时间】:2010-08-19 22:28:50
【问题描述】:

在 MS SQL Server 中,如果我想检查存储过程的结果,我可以在 Management Studio 中执行以下操作。

--SQL SERVER WAY
exec sp_GetQuestions('OMG Ponies')

结果窗格中的输出可能如下所示。

ID    Title                                             ViewCount   Votes 
----- ------------------------------------------------- ---------- --------
2165  Indexed View vs Indexes on Table                  491         2  
5068  SQL Server equivalent to Oracle’s NULLS FIRST     524         3 
1261  Benefits Of Using SQL Ordinal Position Notation?  377         2 

(3 row(s) affected)

无需编写循环或 PRINT 语句。

为了在 Oracle 中做同样的事情,我可能会在 SQL Developer 中执行以下匿名块

--ORACLE WAY
    DECLARE
        OUTPUT  MYPACKAGE.refcur_question;
        R_OUTPUT MYPACKAGE.r_question;
        USER    VARCHAR2(20);

BEGIN

  dbms_output.enable(10000000);
  USER:= 'OMG Ponies';
  recordCount := 0;



  MYPACKAGE.GETQUESTIONS(p_OUTPUT => OUTPUT, 
  p_USER=> USER, 

  ) ;




  DBMS_OUTPUT.PUT_LINE('ID |  Title | ViewCount | Votes' );

  LOOP 
    FETCH OUTPUT
    INTO R_OUTPUT;

         DBMS_OUTPUT.PUT_LINE(R_OUTPUT.QUESTIONID || '|' || R_OUTPUT.TITLE 
               '|' || R_OUTPUT.VIEWCOUNT '|' || R_OUTPUT.VOTES);
          recordCount := recordCount+1;




 EXIT WHEN OUTPUT % NOTFOUND;  
      END LOOP;
      DBMS_OUTPUT.PUT_LINE('Record Count:'||recordCount);
      CLOSE OUTPUT;


    END;

这个输出像

ID|Title|ViewCount|Votes 
2165|Indexed View vs Indexes on Table|491|2  
5068|SQL Server equivalent to Oracle’s NULLS FIRST|524|3 
1261|Benefits Of Using SQL Ordinal Position Notation?|377|2 
Record Count: 3

所以 SQL 版本有 1 行,oracle 有 18 行,输出很难看。如果有很多列和/或数据是数字,它会加剧。

对此我感到奇怪的是,如果我在 SQL Developer 或 Management Studio 中编写此语句...

SELECT 
ID, 
Title, 
ViewCount, 
Votes
FROM votes where user = 'OMG Ponies'  

结果非常相似。这让我觉得我要么错过了一项技术,要么使用了错误的工具。

【问题讨论】:

    标签: oracle oracle10g oracle-sqldeveloper


    【解决方案1】:

    如果GetQuestions 是一个返回引用的函数,这似乎是您在 SQL Server 版本中所拥有的,那么您可以执行以下操作:

    select * from table(MyPackage.GetQuestions('OMG Ponies'));
    

    或者,如果您在 PL/SQL 块中需要它,那么您可以在游标中使用相同的选择。

    您也可以让函数生成 dbms_output 语句,以便它们始终可用于调试,尽管这会增加一点开销。

    编辑

    嗯,不确定是否可以将返回的 refcursor cast() 转换为可用类型,除非您愿意在包外声明自己的类型(以及该类型的表)。你可以这样做,只是为了转储结果:

    create package mypackage as
        function getquestions(user in varchar2) return sys_refcursor;
    end mypackage;
    /
    
    create package body mypackage as
        function getquestions(user in varchar2) return sys_refcursor as
            r sys_refcursor;
        begin
            open r for
                /* Whatever your real query is */
                select 'Row 1' col1, 'Value 1' col2 from dual
                union
                select 'Row 2', 'Value 2' from dual
                union
                select 'Row 3', 'Value 3' from dual;
                return r;
        end;
    end mypackage;
    /
    
    var r refcursor;
    exec :r := mypackage.getquestions('OMG Ponies');
    print r;
    

    并且您可以在另一个过程或函数中使用调用的结果;它只是在 PL/SQL 之外进行,这似乎有点棘手。

    编辑添加:使用这种方法,如果它是一个过程,你可以做同样的事情:

    var r refcursor;
    exec mypackage.getquestions(:r, 'OMG Ponies');
    print r;
    

    【讨论】:

    • SQL Server 版本可能不是函数。在 SQL Server 中,返回类似结果的存储过程只有 select 未绑定到游标的语句。获取此类存储过程的执行结果与在客户端从select 查询中获取结果相同。
    • 有一天我应该了解一下 SQL Server。似乎等价的将是一个返回 refcursor 的函数,而不是一个带有 OUT 参数的过程,所以它可以用于来自计划 SQL 的查询?
    • MyPackage.GetQuestions 是一个过程。例如PROCEDURE GETQUETSIONS(输出 IN OUT MYPACKAGE.refcur_question,用户 IN VARCHAR2)。当我绑定你的技术时,我得到了无效的标识符错误
    • 我在想你可以把它变成一个函数; FUNCTION GETQUESTIONS(user IN VARCHAR2) RETURNS refcur_question。但是您可能无法修改它;从内存中,您可能必须在模式级别定义返回类型(refcur_question),而不是在包内,但已经有一段时间了......
    • 如果您保留现有程序,请尝试exec mypackage.getquestions(:r, 'OMG Ponies');,而不是使用额外的功能来进行转换。我专注于一个函数,因为我认为它会强制转换,但因为它不是一个过程是好的(并且可能更“标准”)。所以你仍然有 3 行替换你原来的 18 *8-)
    【解决方案2】:

    SQL Developer 自动捕获运行存储过程的输出。直接从我们的过程编辑器运行存储过程,您可以在我的帖子中看到此行为的详细说明

    SQL Developer Tip: Viewing REFCURSOR Output

    现在,如果您想在我们的 SQL 工作表中将 refcursor 作为 anon 块的一部分运行,您可以执行类似的操作

    var rc refcursor
    exec :rc := GET_EMPS(30)
    print rc
    

    --其中 GET_EMPS() 将是您的 sp_GetQuestions('OMG Ponies') 调用。 PRINT 命令发送通过存储过程运行的“查询”的输出,如下所示:

    anonymous block completed
    RC
    -----------------------------------------------------------------------------------------------------
    EMPLOYEE_ID FIRST_NAME           LAST_NAME                 EMAIL                     PHONE_NUMBER         HIRE_DATE                 JOB_ID     SALARY     COMMISSION_PCT MANAGER_ID DEPARTMENT_ID 
    ----------- -------------------- ------------------------- ------------------------- -------------------- ------------------------- ---------- ---------- -------------- ---------- ------------- 
    114         Den                  Raphaely                  DRAPHEAL                  515.127.4561         07-DEC-94 12.00.00        PU_MAN     11000                     100        30            
    115         Alexander            Khoo                      AKHOO                     515.127.4562         18-MAY-95 12.00.00        PU_CLERK   3100                      114        30            
    116         Shelli               Baida                     SBAIDA                    515.127.4563         24-DEC-97 12.00.00        PU_CLERK   2900                      114        30            
    117         Sigal                Tobias                    STOBIAS                   515.127.4564         24-JUL-97 12.00.00        PU_CLERK   2800                      114        30            
    118         Guy                  Himuro                    GHIMURO                   515.127.4565         15-NOV-98 12.00.00        PU_CLERK   2600                      114        30            
    119         Karen                Colmenares                KCOLMENA                  515.127.4566         10-AUG-99 12.00.00        PU_CLERK   2500                      114        30            
    

    现在,你说的是 10 克。如果您使用的是 12c,我们增强了 PL/SQL 引擎以支持隐式游标结果。所以这变得更容易了,不再设置游标,您只需调用获取数据,如此处所述: http://docs.oracle.com/database/121/DRDAA/migr_tools_feat.htm#DRDAA230

    【讨论】:

    • 我昨天确实在看这个功能。这很好,但有点像 PIA,因为我不能只打开“运行 PL/SQL”窗口 感谢 12c 提示。我们仍在使用 11G,所以我期待最终使用它。我还修复了您帖子的格式。请参阅Editing-help 了解我是如何做到的
    • 所以您想要一个“运行 PL/SQL”窗口来自动获取输出,就像我们的过程编辑器在执行单个单元时提供的那样?不错的主意...我会在小组周围踢它,看看它的去向。
    【解决方案3】:
    /*
        Create Sample Package in HR Schema
    */
    
    CREATE OR REPLACE PACKAGE PRINT_REF_CURSOR
    AS
        PROCEDURE SP_S_EMPLOYEES_BY_DEPT (
            p_DEPARTMENT_ID   IN  INTEGER,
            Out_Cur OUT SYS_REFCURSOR); 
    
    END PRINT_REF_CURSOR;        
    
    CREATE OR REPLACE PACKAGE BODY PRINT_REF_CURSOR
    AS
    
        PROCEDURE SP_S_EMPLOYEES_BY_DEPT (
            p_DEPARTMENT_ID   IN  INTEGER,
            Out_Cur OUT SYS_REFCURSOR)
        AS 
        BEGIN
          OPEN Out_Cur FOR
               SELECT *
                 FROM EMPLOYEES
                 WHERE DEPARTMENT_ID = p_DEPARTMENT_ID;
        EXCEPTION
          WHEN NO_DATA_FOUND
          THEN
             DBMS_OUTPUT.Put_Line('SP_S_EMPLOYEES_BY_DEPT' || ',' || '-20000' || ',' );
          WHEN OTHERS
          THEN
             DBMS_OUTPUT.Put_Line('SP_S_EMPLOYEES_BY_DEPT' || ',' || '-20001' || ',' );    
        END SP_S_EMPLOYEES_BY_DEPT;         
    
    END PRINT_REF_CURSOR;    
    
    /*
        Fetch values using Ref Cursor and display it in grid.
    */
    
    var RC refcursor;
    
    DECLARE 
        p_DEPARTMENT_ID NUMBER;
        OUT_CUR SYS_REFCURSOR;
    
    BEGIN 
      p_DEPARTMENT_ID := 90;
      OUT_CUR := NULL;
    
      PRINT_REF_CURSOR.SP_S_EMPLOYEES_BY_DEPT ( p_DEPARTMENT_ID, OUT_CUR);
      :RC := OUT_CUR;
    
    END;
    /
    PRINT RC;  
    /************************************************************************/  
    

    【讨论】:

      猜你喜欢
      • 2011-04-15
      • 2019-09-15
      • 1970-01-01
      • 2013-10-18
      • 2011-01-24
      • 2014-03-12
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      相关资源
      最近更新 更多