Plsql 在Oracle10gv2中使用sys_refcursor发送嵌套表

Plsql 在Oracle10gv2中使用sys_refcursor发送嵌套表,plsql,cursor,oracle10g,nested-table,sys-refcursor,Plsql,Cursor,Oracle10g,Nested Table,Sys Refcursor,我需要使用sys\u refcursor向Jasper Reports发送一些数据。此数据是pl/sql中查询和查询结果评估的结果。其思想是通过同一个表中的多个列对一些值进行过滤,但由于过滤限制,在使用Subselect的查询中无法对这些值进行计数。对不起,我不太清楚,但我有保密协议。但是,我可以发布一些代码并解释我必须实现的功能的重要部分。该项目基于Java,使用Oracle 10gv2和JasperReports 3.6.1,无法更新(因此没有Oracle v12) 我有一个关联数组的过程,

我需要使用sys\u refcursor向Jasper Reports发送一些数据。此数据是pl/sql中查询和查询结果评估的结果。其思想是通过同一个表中的多个列对一些值进行过滤,但由于过滤限制,在使用Subselect的查询中无法对这些值进行计数。对不起,我不太清楚,但我有保密协议。但是,我可以发布一些代码并解释我必须实现的功能的重要部分。该项目基于Java,使用Oracle 10gv2和JasperReports 3.6.1,无法更新(因此没有Oracle v12)

我有一个关联数组的过程,数组中填充了我必须返回的键和值。键表示与目标报告上的每个列类型关联的筛选结果,值是必须填充正确列的数字。下面是创建关联数组的过程和声明

create or replace PROCEDURE test_proc02(test_cursor OUT sys_refcursor) IS

    /* associative arrays declaration */

    TYPE transfer_type IS TABLE OF NUMBER
        INDEX BY VARCHAR2(10);
    transfer_table transfer_type; 
但其中一个问题是,我不能将关联数组与sys_refcursor一起使用,如下所示:

Select * from table(cast(transfer_table AS transfer_type))
Key       value
--------------
A548521     5
A325411     12
A329471     9
因此,我将关联数组值复制到一个嵌套表中,相信前面的select将使用该结构。这是代码的一部分

/* nested table declaration */

TYPE transfer_nt_type IS TABLE OF VARCHAR2(20);

/* nested table initilization */
transfer_nt transfer_nt_type := transfer_nt_type();

/* some variables */
transfer_id VARCHAR2(10);
transfer_number NUMBER;
nt_counter INTEGER := 0;
nt_iter VARCHAR2(10);


/* copying AA into NT */
nt_iter := transfer_table.FIRST;
WHILE (nt_iter IS NOT NULL)
LOOP        
    nt_counter := nt_counter+1;
    transfer_nt.EXTEND;
    transfer_nt(nt_counter):=transfer_table(nt_iter);
    dbms_output.put_line('nested table ('||nt_counter||'): '||transfer_nt(nt_counter));
    nt_iter := transfer_table.NEXT(nt_iter);
END LOOP;

/* Trying to send NT to JR */
OPEN travelCursor FOR SELECT * FROM TABLE(cast(transfer_nt AS transfer_nt_type));

/* ERROR */
PLS-00382: expression is of wrong type
我不关心这个方法,我只想把数据发送给JR生成一个报告,所以如果我必须替换完整的过程结构,我也可以。我已经在stackoverflow和其他来源中搜索了好几天,但似乎没有任何结果,所以我不确定我所有的概念想法是否都是错误的

有什么想法吗?谢谢

编辑:

传输类型的类型声明错误,是从以前的版本复制的。现在它是正确的。机管局的数据如下:

Select * from table(cast(transfer_table AS transfer_type))
Key       value
--------------
A548521     5
A325411     12
A329471     9
成对的总数为32,键为varchar2(10),值为数字。最终嵌套表的内容(VARCHAR(20))为:

A548521#5,A325411#12,A329471#9
该类型是在架构级别声明的。我也试过:

OPEN travelCursor FOR 
        SELECT CAST(MULTISET(
            SELECT * FROM TABLE(transfer_nt)
            ORDER BY 1) AS transfer_nt_type)
        INTO transfer_nt_out FROM DUAL;
同样的结果。这两种数据结构都经过测试,并以dbms_输出完美打印,结构中的数据是正确的。如果可能的话,我至少需要按照给定的顺序发送值。如果我可以在值响应中保持一定的顺序,则键并不重要

编辑以反映Alex Poole提案。在程序开始之前:

FUNCTION transfer_func (transfer_table transfer_type)RETURN transfer_nt_type PIPELINED IS

      --TYPE transfer_type IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
      --transfer_table transfer_type; 

      nt_iter VARCHAR2(10);

      BEGIN

          nt_iter := transfer_table.FIRST;
          WHILE (nt_iter IS NOT NULL)
          LOOP
            PIPE ROW (nt_iter || '#' || transfer_table(nt_iter));
            nt_iter := transfer_table.NEXT(nt_iter);
          END LOOP;

    END transfer_func;
程序结束前:

OPEN travelCursor for select * from table(transfer_func(transfer_table));
同样的错误:

PLS-00382: expression is of wrong type
最终编辑和解决方案:

最后,我用GTT解决了这个问题。我不知道为什么,但在我第一次尝试这种方法时,Oracle Developer返回了与其他可能的解决方案相同的错误。我尝试了最古老的方法:关闭程序,重新设置机器,从头开始。这样就成功了!当然,只有GTT

nt_iter := transfer_table.FIRST;
WHILE (nt_iter IS NOT NULL)
LOOP        
        nt_counter := nt_counter+1;
        INSERT INTO transfer_temp VALUES(nt_iter,transfer_table(nt_iter),06);

        nt_iter := transfer_table.NEXT(nt_iter);
END LOOP;

    OPEN test_cursor FOR select * from transfer_temp order by transfer_temp.id;

CREATE GLOBAL TEMPORARY TABLE transfer_temp (
        id           VARCHAR(20),
        value         NUMBER,
        month         NUMBER
        )
        ON COMMIT PRESERVE ROWS;
谢谢大家的帮助

一个(可能性能较低)简单的解决方案是将结果写入一个临时表,然后

OPEN travelCursor FOR SELECT * FROM That_Temp_Table;

您可以改用流水线函数,使用架构级表类型:

create or replace TYPE transfer_nt_type AS TABLE OF VARCHAR2(20)
/

create or replace FUNCTION test_func02
RETURN transfer_nt_type PIPELINED IS

  TYPE transfer_type IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
  transfer_table transfer_type; 

  nt_iter VARCHAR2(10);

BEGIN

  -- sample data
  transfer_table('A548521') := 5;
  transfer_table('A325411') := 12;
  transfer_table('A329471') := 9;

  nt_iter := transfer_table.FIRST;
  WHILE (nt_iter IS NOT NULL)
  LOOP
    PIPE ROW (nt_iter || '#' || transfer_table(nt_iter));
    nt_iter := transfer_table.NEXT(nt_iter);
  END LOOP;

  RETURN;

END test_func02;
/
然后你可以做:

select * from table(test_func02);
其中包括:

Result Sequence     
--------------------
A325411#12
A329471#9
A548521#5
如果限制为ref游标,则可以添加包装程序:

create or replace PROCEDURE test_proc02(test_cursor OUT sys_refcursor) IS
BEGIN

  OPEN test_cursor FOR SELECT * FROM TABLE(test_func02);

END test_proc02;
/

var rc refcursor;

exec test_proc02(:rc);

print rc;

Result Sequence     
--------------------
A325411#12
A329471#9
A548521#5

我相信你有问题,因为:

1) 您在过程中定义了类型

所以尝试创建上面示例中的类型

2) 在索引表上使用select*from

如果需要在嵌套表中存储2个值,请使用类似记录的

CREATE OR REPLACE TYPE "TSTRING2LIST_RECORD" AS OBJECT
(
  column1_value VARCHAR2(4000),
  column2_value VARCHAR2(4000)
)
/

CREATE OR REPLACE TYPE "TSTRING2LIST_TABLE" IS TABLE OF TSTRING2LIST_RECORD
/
在这之后,您可以在过程中声明它并使用它,无论您想要什么,我下面的代码可能会被破坏,因为我编写它时没有IDE,但您需要了解我的想法:

PROCEDURE idk(cur out sys_refcursor) IS
  l_table tstring2list_table := tstring2list_table();

BEGIN
  l_table.extend;
  l_table(l_table.count) := tstring2list_record('idx1', 'value1');
  l_table.extend;
  l_table(l_table.count) := tstring2list_record('idx2', 'value2');
  l_table.extend;
  l_table(l_table.count) := tstring2list_record('idx3', 'value3');

  OPEN cur for select column2_value from table(l_table);
END;
您还可以使用大容量收集或动态SQL或其他方式:

SELECT tstring2list_record(t.col1, t.col2) BULK COLLECT
  INTO l_table
  FROM some_table t

为了使该类型可用于SQL引擎,您需要在架构级别声明该类型,而不是作为过程的一部分。例如,
创建或替换类型…
感谢您的快速回答!在发布问题之前,我尝试过这样做,但没有任何改变,同样的错误。如果您可以发布一个完整的测试用例来演示您的问题,那将更有帮助。您是否使用相同的名称创建了架构级别的类型
transfer\nt\u type
-如果是,您是否删除/注释掉了PL/SQL类型定义?按照建议进行编辑,但是没有什么信息可以补充。谢谢你的回答。但是,此解决方案可能会产生严重的性能问题。如果这是我认为它将被批准的唯一方式,但我相信一定有另一种方式,可能是另一种数据结构转换或其他方式。@RafaJ,上面的流水线操作可能更有趣。谢谢!我试图实现类似于您的解决方案的东西,但我不理解如何使用流水线函数。使用您的代码,我重新编码了该解决方案,没有语法错误,但最终错误与以前相同。至少现在我知道如何正确地执行流水线函数了!我将编辑最初的帖子以反映这一尝试,也许这不是正确的实现。我没有10gR2 DB可供测试,但这在11gR2上有效,我无法发现我记得在这些版本之间发生的任何更改。哪一行抛出错误?(不管怎样,将PL/SQL的完整错误堆栈放在问题中通常是有帮助的…)我认为您不能将transfer_类型传递到函数调用中(不管怎样,从SQL语句传递),因为这是PL/SQL类型。在我的版本中,我在函数中定义并填充
transfer\u类型
,而不是传入它。你的问题不清楚关联数组来自何处。你是对的,这是尝试更改的最快方法。我认为,如果一个函数可以接受refcursor,正如我在一些示例中看到的那样,我的transfer\u类型也将是正确的。我将尝试重新构建程序以模仿你的建议。但我认为错误可能是另一回事。我尝试了GTT,正确地填充了它,并尝试使用光标。同样的错误。@AlexPoole是您的函数实际工作的。我的意思是
return
缺失