Как получить хорошо отформатированные результаты из процедуры 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'
Результаты довольно схожи. Это заставляет меня чувствовать, что я либо пропустил технику, либо использовал неправильный инструмент.
Ответы
Ответ 1
Если GetQuestions
- это функция, возвращающая refcursor, что похоже на то, что у вас есть в версии 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;
Ответ 2
SQL Developer автоматически улавливает вывод из запуска хранимых процедур. Запуск хранимой процедуры непосредственно из нашего редактора процедур, вы можете увидеть это поведение подробно в моем сообщении здесь
Совет разработчика SQL: просмотр вывода REFCURSOR
Теперь, если вы хотите запустить refcursor как часть блока анонов в нашем рабочем листе 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
Теперь вы сказали 10g. Если вы находитесь в 12c, мы улучшили механизм PL/SQL для поддержки неявных результатов курсора. Таким образом, это становится немного легче, больше не настраивая курсор, вы просто делаете вызов для получения данных, как описано здесь:
http://docs.oracle.com/database/121/DRDAA/migr_tools_feat.htm#DRDAA230
Ответ 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;
/************************************************************************/