在不更改光标位置的情况下检查SQL SYS_REFCURSOR

时间:2020-09-18 07:44:29

标签: sql oracle stored-procedures cursor

我有一个要求检查游标是否能够从表A中获取一些行。如果是,则别无选择,从表B中提取行。 当前,目前有两个存储过程。 我试图在一个存储过程中做到这一点。 我尝试使用%ROWCOUNT,但在不更改光标位置的情况下不起作用(因为它将返回0)。 问题是我的输出是光标,所以我不想对其进行任何更改。 如果我进行访存,则返回类型已更改也显示错误。 任何想法如何做到这一点,就像创建一个游标一样,以便可以在副本上而不是在输出游标上进行获取和行计数。 伪示例

create or replace PROCEDURE "proc"
(
    output OUT SYS_REFCURSOR,
)
.
BEGIN
.
.
OPEN output for select * from A
END

BEGIN
//check if output was empty then
OPEN output for select * from B

.
.
END

更新: 我按照建议做了

....
BEGIN
...
OPEN output for 
  with 
    A as (select ...),
   ,B as (select ...),
   ,C as (select ...),
   ,D as (select ...)
  select * from A
   union 
  select * from B where not exists(select null from A)
   union 
  select * from C where not exists(select null from B)
   union 
  select * from D where not exists(select null from C)
END;

由于我确定这些表中的任何一个都有数据,因此我也尝试了以下方法

....
BEGIN
...
OPEN output for 
  with 
    A as (select ...)
   ,B as (select ...)
   ,C as (select ...),
   ,D as (select ...)
  select * from A
   union 
  select * from B
   union 
  select * from C
   union 
  select * from D 
END;

但是这给了我错误 错误(64,7):PL / SQL:ORA-01789:查询块的结果列数不正确 这些4的表结构是不同的。因此,他们可能会返回差异列。 如果4个中有3个为空,那么加入会有意义吗?

1 个答案:

答案 0 :(得分:0)

最好在同一个游标中实现您的要求,因为它将使用相同的时间点读取一致性:在您的方法中,第二个open打开游标的时间与第一个游标不同,实际上A和B中的数据已经可以更改。

这种方法更好:

create or replace PROCEDURE "proc"( output OUT SYS_REFCURSOR,...)
....
BEGIN
...
OPEN output for 
  with 
    A as (select ...)
   ,B as (select ...)
  select * from A
   union all
  select * from B where not exists(select null from A)
END;

另一种可能的解决方案是创建流水线表,例如:

create or replace function ... return {collection type} PIPELINED as
...flag boolean := true;
begin
....
  for i in (select * from A) loop
    flag:=false;
    pipe row(...)
  end loop;
  if flag then
    for i in (select * from B) loop
      flag:=false;
      pipe row(...)
    end loop;
  end if;
end;
/

但是您可以看到两个查询也在不同的时间打开。