Как получить красиво отформатированные результаты из процедуры Oracle, которая возвращает ссылочный курсор? - PullRequest
19 голосов
/ 20 августа 2010

В 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 строку, а оракул - 18, а вывод уродлив. Это усугубляется, если столбцов много и / или данные числовые.

Что странно для меня, так это то, что если я напишу это утверждение в SQL Developer или Management studio ...

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

Результаты довольно схожи. Это заставляет меня чувствовать, что я либо пропускаю технику, либо использую не тот инструмент.

Ответы [ 3 ]

17 голосов
/ 20 августа 2010

Если GetQuestions - это функция, возвращающая рефкурсор, который, по-видимому, является тем, что есть в версии SQL Server, то, скорее всего, вы сможете сделать что-то вроде этого:

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

Или, если вам это нужно в блоке PL / SQL, вы можете использовать тот же самый выбор в курсоре.

Вы также можете заставить функцию генерировать операторы dbms_output, чтобы они всегда были доступны для отладки, хотя это добавляет немного накладных расходов.

Редактировать

Хммм, не уверен, что cast() можно вернуть возвращаемый refcursor для пригодного для использования типа, если вы не хотите объявить свой собственный тип (и таблицу этого типа) вне пакета. Вы можете сделать это, хотя бы, чтобы вывести результаты:

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;
1 голос
/ 23 июля 2014

SQL Developer автоматически перехватывает выходные данные при запуске ваших хранимых процедур. Запустив хранимую процедуру прямо из нашего редактора процедур, вы можете увидеть это поведение подробно в моем посте здесь

Совет разработчика SQL: просмотр вывода REFCURSOR

Теперь, если вы хотите запустить refcursor как часть блока anon в нашей рабочей таблице SQL, вы можете сделать что-то похожее на это

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

0 голосов
/ 01 февраля 2014
/*
    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;  
/************************************************************************/  
...