Return 基于一个查询的游标的 2 个结果集(嵌套游标)

Return 2 resultset from cursor based on one query (nested cursor)

我正在尝试根据单个查询从存储过程中获取 2 个不同的结果集。我想做的是:

1.) return查询结果存入OUT游标;

2.) 从此游标结果中,获取每一列中所有最长的值,并且 return 作为第二个 OUT 结果集。

我试图避免用这个做同样的事情两次 - 获取数据,然后获取相同数据的最长列值。我不确定这是否可能,但如果可能,有人可以告诉我怎么做吗?

这是我想要做的一个例子(仅供说明):

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: table 或视图不存在”编译。

我知道这是一个愚蠢的例子,但我一直在调查和测试各种东西(隐式游标、获取游标、嵌套游标等),但没有发现任何对我有帮助的东西,特别是在使用存储的时候过程 returning 多个结果集。

我的总体目标是缩短 Excel 的数据导出时间。目前我必须 运行 两次相同的查询 - 一次计算数据大小以自动适应 Excel 列,然后将数据写入 Excel。

我相信操作第一个结果集以获得第二个结果集会更快 - 减少数据库周期。

我正在使用 Oracle 11g,非常感谢任何帮助。

游标中的每一行数据只能被读取一次;一旦从游标中读取了下一行(或一组行),则无法返回前一行(或一组行)并且无法重新使用游标。所以你问的是不可能的,就好像你读取游标来找到最大值一样(忽略你不能在 SELECT 语句中使用游标作为源但是,相反,你可以使用 PL/SQL 循环)那么游标的行将是 "used up" 并且游标关闭,因此当它从过程返回时无法读取。

您需要使用两个单独的查询:

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

仅出于理论目的,如果您将数据批量收集到集合中,则可以仅从 table 中读取一次,然后从 table 集合表达式中读取 select(但是,code/maintain 会更复杂,并且需要将 table 中的行存储在内存中 [如果 table 很大,您的 DBA 可能不会欣赏] 并且可能不会比仅查询 table 两次更高效,因为您最终会得到三个 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;
/