如何编写一个存储过程,将列添加到另一个存储过程的引用游标?

时间:2016-02-18 15:20:13

标签: oracle stored-procedures plsql oracle11g

我有一个存储过程GetRegions,它将一些列提取到游标中,如下所示:

OPEN out_cur FOR
    SELECT id, name, ...
      FROM regions, ...
     WHERE ...

这个SP在整个地方使用 - 在将返回数十个区域的地方以及将返回数万个地方的地方。

我还有一个函数GetRegionPath,它可以获取某个区域的“路径”。这是一个中等昂贵的功能 - 在几十个地区运行它没有问题,但数万个是不可接受的。

我需要编写一个存储过程GetRegionsWithPaths,它可以获得完全相同逻辑的区域,现在和永远GetRegions,但其中包含的路径为结果集中的区域。

目前,GetRegionsWithPathsGetRegions的精确副本,并添加了路径:

OPEN out_cur FOR
    SELECT id, name, ..., GetRegionPath(id) path
      FROM regions, ...
     WHERE ...

但这是不可接受的 - 如果有人编辑GetRegions,则两个SP将不同步。我想要的是从GetRegions取光标然后添加它的路径。类似的东西:

GetRegions(..., v_cur);

OPEN out_cur FOR
    SELECT id, name, ..., GetRegionPath(id) path
        FROM ( SELECT * FROM v_cur );

这可能吗?如果是这样,语法是什么?

2 个答案:

答案 0 :(得分:1)

一种可能的解决方案(最终可以简化)是使用表函数来处理游标并添加函数值。

假设返回sys_refcursor的函数被称为get_cur,并且游标由列ID, NAME组成(这很重要,因为表函数需要类型定义)。

您声明行的TYPE(包括附加路径列)和结果表。

create type t_row is object
 ( id             number(10),
   name varchar2(10),
   path varchar2(10)
);
/

create type t_rows is table of t_row;
/

并定义表函数获取光标并添加函数调用。

create or replace function get_cur2  return 
t_rows
PIPELINED
as
   cv_out     sys_refcursor;
   id   number;
   name   varchar2(100);    
begin
      cv_out := get_cur; 
      loop 
        FETCH cv_out INTO id, name;
        exit when cv_out%NOTFOUND;
        pipe row(t_row(id,name, GetRegionPath(id)));
      end loop;
      close    cv_out;
      return;
end;
/

现在您可以从表格函数中选择数据

select * from  table(get_cur2); 

        ID NAME       PATH     
---------- ---------- ----------
         1 one        path 1     
         2 two        path 2 

当然您可以使用此查询在第三个函数中打开游标,该函数将返回带有附加路径列的SYS_REFCURSOR。

答案 1 :(得分:1)

使用评论中建议的参数进行替代实施。

假设原始函数看起来像这样

create or replace function get_cur return SYS_REFCURSOR is
cv_out     sys_refcursor;
begin
 OPEN cv_out  
      FOR 
      select   Id,   name from tab;
 return cv_out;
end;
/

您添加一个参数return_path,该参数为0 - 返回原始光标或1 - 这将返回带有路径列的原始curosr。

实施可能就像这样

create or replace function get_cur_with_param(return_path NUMBER) return SYS_REFCURSOR is
cv_out     sys_refcursor;
v_stmt_str      VARCHAR2(4000);
begin
 v_stmt_str := 'select   Id,   name '||case when return_path = 1 then ', GetRegionPath(id)' end ||' from tab';
 OPEN cv_out  FOR v_stmt_str; 
 return cv_out;
end;
/

get_cur_with_param(0)返回2列游标,get_cur_with_param(1)返回添加了path列的游标。

请注意,SQL是动态构建的,但只会以两个变体结束,因此解析时没问题。如果查询中有其他参数,请使用绑定变量添加USING子句。