Plsql 在Oracle10gv2中使用sys_refcursor发送嵌套表
我需要使用sys\u refcursor向Jasper Reports发送一些数据。此数据是pl/sql中查询和查询结果评估的结果。其思想是通过同一个表中的多个列对一些值进行过滤,但由于过滤限制,在使用Subselect的查询中无法对这些值进行计数。对不起,我不太清楚,但我有保密协议。但是,我可以发布一些代码并解释我必须实现的功能的重要部分。该项目基于Java,使用Oracle 10gv2和JasperReports 3.6.1,无法更新(因此没有Oracle v12) 我有一个关联数组的过程,数组中填充了我必须返回的键和值。键表示与目标报告上的每个列类型关联的筛选结果,值是必须填充正确列的数字。下面是创建关联数组的过程和声明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) 我有一个关联数组的过程,
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
缺失