如何从返回参考光标的Oracle过程中得到格式良好的结果?

在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' 

结果非常相似。 这使我觉得我要么缺less一种技术,要么使用错误的工具。

如果GetQuestions是一个返回refcursor的函数,这似乎是你在SQL Server版本中的东西,那么你也许可以这样做:

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

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

你也可以让这个函数生成dbms_output语句,所以它们总是可用于debugging,尽pipe这会增加一些开销。

编辑

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

 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 Developer自动捕获运行存储过程的输出。 直接从我们的过程编辑器运行存储过程,你可以在我的文章中看到这个行为

SQL Developer提示:查看REFCURSOR输出

现在,如果你想在我们的SQL工作表中运行refcursor作为匿名块的一部分,你可以做类似于这个

 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 

现在,你说10g。 如果你在12c中,我们已经增强了PL / SQL引擎来支持隐式游标结果。 因此,这变得更容易,不再设置光标,只需拨打电话即可获取数据,如下所述: http : //docs.oracle.com/database/121/DRDAA/migr_tools_feat.htm#DRDAA230

 /* 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; /************************************************************************/