我需要使用sys_refcursor将一些数据发送到Jasper Reports . 此数据是查询结果和pl / sql中查询结果的评估结果 . 我们的想法是计算一些值在同一个表中按几列过滤,并且由于过滤限制而无法在具有子选择的查询中完成 . 很抱歉不是很清楚,但我是在NDA下 . 但是,我可以发布一些代码并解释我必须实现的功能的重要部分 . 该项目基于Java并使用Oracle 10gv2和JasperReports 3.6.1,但无法更新(因此没有Oracle v12) .
我有一个关联数组的过程,其中填充了键和我必须返回的值 . Keys表示与目标报表上的每个列类型关联的过滤结果,值是必须填充正确列的数字 . 这是过程创建和关联数组的声明 .
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))
因此,我将关联数组值复制到嵌套表中,认为先前的选择将适用于该结构 . 这是代码的一部分
/* 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生成报告,所以如果我必须更换完整的Procedure结构就可以了 . 我在stackoverflow和其他来源搜索了几天,但似乎没有任何工作,所以我不确定我的所有概念想法是否都是错误的 .
有任何想法吗?谢谢 .
编辑:
transfer_nt_type的Type声明错误,从先前版本复制 . 现在这是正确的 . AA的数据是这样的:
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_output测试和打印,完美无缺,结构内的数据是正确的 . 如果可能的话,我至少需要以给定的顺序发送值 . 如果我可以在值响应中维护某个顺序,则键不重要 .
编辑以反映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
Final edit and solution:
最后我用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;
谢谢大家的帮助!
3 回答
然后,一个(可能是低性能)的简单解决方案是将结果写入临时表
您可以使用流水线函数,使用模式级表类型:
然后你可以这样做:
获得:
如果您被限制为引用游标,则可以添加包装程序:
我相信你有问题,因为:
所以尝试创建类似上面的例子
如果你需要在嵌套表中存储2个值,那么创建记录类型的记录类型表
之后你可以在你的程序中声明它并使用它你想要的任何东西,下面的代码可能会破坏,因为我没有IDE写它,但你需要 grab 我的想法:
您还可以使用批量收集或动态SQL或其他: