Возврат 2 результатов из курсора на основе одного запроса (вложенный курсор) - PullRequest
0 голосов
/ 15 января 2020

Я пытаюсь получить 2 разных набора результатов из хранимой процедуры на основе одного запроса. Я пытаюсь сделать следующее:

1.) Вернуть результат запроса в курсор OUT;

2.) Из результатов этого курсора, получить все самые длинные значения в каждом столбце и вернуть как второй OUT resultset.

Я пытаюсь избежать повторения одного и того же с этим дважды - получаю данные, а после этого получаю самые длинные значения столбцов этих же данных. Я не уверен, если это вообще возможно, но если это так, может кто-нибудь показать мне, КАК?

Это пример того, что я хочу сделать (только для иллюстрации):

CREATE OR REPLACE PROCEDURE MySchema.Test(RESULT OUT SYS_REFCURSOR,MAX_RESULT OUT SYS_REFCURSOR)
AS

BEGIN

 OPEN RESULT FOR SELECT Name,Surname FROM MyTable; 

 OPEN MAX_RESULT FOR SELECT Max(length(Name)),Max(length(Surname)) FROM RESULT; --error here 

END Test;

Этот пример компилируется с « ORA-00942: таблица или представление не существует ».

Я знаю, что это глупый пример, но я изучал и тестировал все виды вещи (неявные курсоры, выборочные курсоры, вложенные курсоры и т. д. c.) и не нашли ничего, что могло бы мне помочь, особенно при работе с хранимой процедурой, возвращающей несколько наборов результатов.

Моя общая цель - сократить данные время экспорта в Excel. В настоящее время я должен выполнить один и тот же запрос дважды - один раз для расчета размера данных для автоматического подбора столбцов Excel, а затем для записи данных в Excel.

Я считаю, что манипулирование первым набором результатов с целью получения второго было бы намного быстрее - с меньшим количеством циклов БД.

Я использую Oracle 11g, Любая помощь очень ценится.

1 Ответ

2 голосов
/ 15 января 2020

Каждая строка данных из курсора может быть прочитана ровно один раз; как только следующая строка (или набор строк) считывается из курсора, предыдущая строка (или набор строк) не может быть возвращена и курсор не может быть повторно использован. Поэтому то, что вы спрашиваете, невозможно, как будто вы читаете курсор, чтобы найти максимальные значения (игнорируя то, что вы не можете использовать курсор в качестве источника в операторе SELECT, но вместо этого вы можете прочитать его с помощью PL / SQL l oop) тогда строки курсора были бы "использованы", а курсор закрыт, поэтому его нельзя было прочитать, когда он возвращается из процедуры.

Вам потребуется использовать два отдельных запросы:

CREATE PROCEDURE MySchema.Test(
  RESULT     OUT SYS_REFCURSOR,
  MAX_RESULT OUT SYS_REFCURSOR
)
AS
BEGIN
 OPEN RESULT FOR
   SELECT Name,
          Surname
   FROM   MyTable; 

 OPEN MAX_RESULT FOR
   SELECT MAX(LENGTH(Name))    AS max_name_length,
          MAX(LENGTH(Surname)) AS max_surname_length
   FROM   MyTable;
END Test;
/

Только для теоретических целей чтение из таблицы возможно только один раз, если вы собираете данные в коллекцию, а затем выбираете из выражения набора таблиц (однако это быть более сложным для кодирования / обслуживания и потребует, чтобы строки из таблицы были сохранены в памяти [что может не понравиться вашему администратору базы данных, если таблица большая) и могут быть не более производительными, чем по сравнению с простым запросом таблицы дважды в итоге вы получите три SELECT утверждения вместо двух).

Что-то вроде:

CREATE TYPE test_obj IS OBJECT(
  name    VARCHAR2(50),
  surname VARCHAR2(50)
);

CREATE TYPE test_obj_table IS TABLE OF test_obj;
CREATE PROCEDURE MySchema.Test(
  RESULT     OUT SYS_REFCURSOR,
  MAX_RESULT OUT SYS_REFCURSOR
)
AS
 t_names test_obj_table;
BEGIN
 SELECT Name,
        Surname
 BULK COLLECT INTO t_names
 FROM   MyTable; 

 OPEN RESULT FOR
   SELECT * FROM TABLE( t_names );

 OPEN MAX_RESULT FOR
   SELECT MAX(LENGTH(Name))    AS max_name_length,
          MAX(LENGTH(Surname)) AS max_surname_length
   FROM   TABLE( t_names );
END Test;
/
...