如何从游标中获取记录
Posted
技术标签:
【中文标题】如何从游标中获取记录【英文标题】:How to fetch the record from cursor 【发布时间】:2016-01-07 09:54:35 【问题描述】:我正在尝试使用 PL SOL 游标从 Oracle 获取一些记录。这是我的代码,
程序参数:
PT_CLAIMS IN CLIM_BEAN_TAB,
PO_CLAIMS_CUSROR OUT SYS_REFCURSOR
迭代代码:
FOR I IN 1 .. PT_CLAIMS.LAST LOOP
SELECT SEQ_TB_CLIAM.NEXTVAL INTO CLAIM_ID FROM DUAL;
INSERT INTO TL_CLAIMS
(
CLAIM_ID,
CLAIM_USER,
CLAMIANT_ID
)
VALUES(
CLAIM_ID,
PT_CLAIMS(I).USER_ID,
PT_CLAIMS(I).CLAMIANT_ID
);
OPEN PO_CLAIMS_CUSROR FOR
SELECT CLAIM_ID AS CALIM_ID FROM DUAL;
end loop;
我在 java 中使用 Out 游标。但是每当我使用 ResultSet 迭代出游标时,我只会得到一条记录。
如何将值添加到循环中的光标。
【问题讨论】:
【参考方案1】:每次循环 IN 表内容时,您都会重新打开 OUT sys_refcursor。每次丢弃前一个 refcursor 并创建一个新的。 (希望 Oracle 在后台正确清理废弃的)。
当循环退出时,OUT 参数的声明 ID 对应于 IN 表中的最后一个条目。您不会将每个声明 ID 添加到单个 OUT refcursor - 您不能这样做。
您可以维护生成的 ID 的本地表,然后在循环之后从该本地表中打开 OUT 游标。或者,您可以在 forall
循环中用单个插入语句替换循环,以允许您使用 returning bulk collect into
:
create procedure p42(pt_claims in claim_bean_tab,
po_claims_cursor out sys_refcursor)
as
l_claim_ids sys.odcinumberlist;
begin
forall i in 1..pt_claims.count
insert into tl_claims(claim_id, claim_user_id, claimant_id)
values (seq_tb_claim.nextval, pt_claims(i).user_id, pt_claims(i).claimant_id)
returning claim_id bulk collect into l_claim_ids;
open po_claims_cursor for
select column_value from table(l_claim_ids);
end;
/
这使用了一个预定义的类型,它是一个数字的可变数组;因为它是一种 SQL 类型,所以它可以与table()
一起使用(作为table collection expression)。
SQL 小提琴似乎又被打破了,所以一个完整的工作示例:
create type claim_bean as object (user_id number, claimant_id number);
/
create type claim_bean_tab as table of claim_bean;
/
create table tl_claims (claim_id number, claim_user_id number, claimant_id number)
/
create sequence seq_tb_claim;
/
create procedure p42(pt_claims in claim_bean_tab,
po_claims_cursor out sys_refcursor)
as
l_claim_ids sys.odcinumberlist;
begin
forall i in 1..pt_claims.count
insert into tl_claims(claim_id, claim_user_id, claimant_id)
values (seq_tb_claim.nextval, pt_claims(i).user_id, pt_claims(i).claimant_id)
returning claim_id bulk collect into l_claim_ids;
open po_claims_cursor for
select column_value from table(l_claim_ids);
end;
/
set serveroutput on
declare
l_claims claim_bean_tab;
l_claims_cursor sys_refcursor;
l_claim_id tl_claims.claim_id%type;
begin
l_claims := new claim_bean_tab();
l_claims.extend(3);
l_claims(1) := new claim_bean(42, 123);
l_claims(2) := new claim_bean(57, 456);
l_claims(3) := new claim_bean(13, 789);
p42(l_claims, l_claims_cursor);
loop
fetch l_claims_cursor into l_claim_id;
exit when l_claims_cursor%notfound;
dbms_output.put_line('Got claim ID from cursor: ' || l_claim_id);
end loop;
close l_claims_cursor;
end;
/
select * from tl_claims
/
PL/SQL procedure successfully completed.
Got claim ID from cursor: 1
Got claim ID from cursor: 2
Got claim ID from cursor: 3
【讨论】:
谢谢亚历克斯。然后如何在我的循环之前打开我的光标并在我的循环中插入值。 @sasikumar - 你不能修改游标,它是一个指向结果集的指针,而不是你可以添加或修改的东西。我添加了一个带有returning
子句的批量插入示例,它将生成的序列 ID 放入本地表中,然后您可以将其用于引用光标。【参考方案2】:
这是因为您正在从变量中提取声明 ID,如果您想提取插入到表中的所有声明 ID,请使用 select claim_id from TL_CLAIMS
。如果要提取表中存在的所有 CLAIM_ID,则必须在循环外打开光标。
FOR I IN 1 .. PT_CLAIMS.LAST LOOP
SELECT SEQ_TB_CLIAM.NEXTVAL INTO CLAIM_ID FROM DUAL;
INSERT INTO TL_CLAIMS
(
CLAIM_ID,
CLAIM_USER,
CLAMIANT_ID
)
VALUES(
CLAIM_ID,
PT_CLAIMS(I).USER_ID,
PT_CLAIMS(I).CLAMIANT_ID
);
end loop;
OPEN PO_CLAIMS_CUSROR FOR
SELECT CLAIM_ID FROM TL_CLAIMS;
更新: 或者,如果您想获取代码中生成的所有声明 ID 的列表,那么您可以编写类似这样的内容。
FOR I IN 1 .. PT_CLAIMS.LAST LOOP
SELECT SEQ_TB_CLIAM.NEXTVAL INTO CLAIM_ID FROM DUAL;
IF I = 1 THEN
l_first_claim_id := CLAIM_ID;
END IF;
INSERT INTO TL_CLAIMS
(
CLAIM_ID,
CLAIM_USER,
CLAMIANT_ID
)
VALUES(
CLAIM_ID,
PT_CLAIMS(I).USER_ID,
PT_CLAIMS(I).CLAMIANT_ID
);
end loop;
OPEN PO_CLAIMS_CUSROR FOR
SELECT l_first_claim_id + ROWNUM - 1
FROM dual
CONNECT BY ROWNUM <= (CLAIM_ID - l_first_claim_id) + 1;
PS:这里的条件是没有来自另一个会话的同时呼叫。
【讨论】:
如果有两个同时调用,每个都必须得到一组连续的 ID 吗?【参考方案3】:SELECT CLAIM_ID AS CALIM_ID FROM DUAL;
将总是返回一行,因为DUAL
只有一行。所以PO_CLAIMS_CUSROR
返回一行是预期的行为。
【讨论】:
以上是关于如何从游标中获取记录的主要内容,如果未能解决你的问题,请参考以下文章