oracle – 通过拆分成多个游标来重构大型游标查询

前端之家收集整理的这篇文章主要介绍了oracle – 通过拆分成多个游标来重构大型游标查询前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
另一个PL / sql重构问题!

我有几个通用简化形式的游标:

cursor_1 is
  with X as (select col1,col2 from TAB where col1 = '1'),Y as (select col1,col2 from TAB where col2 = '3'),/*main select*/
  select count(X.col1),...
  from X inner join Y on...
  group by rollup (X.col1,...

cursor_2 is
  with X as (select col1,col2 from TAB where col1 = '7' and col2 = '9' and col3 = 'TEST'),col2 from TAB where col3 = '6'),...


cursor_2 is
  with X as (select col1,col2 from TAB where col1 IS NULL ),col2 from TAB where col2 IS NOT NULL ),...


...
begin
    for r in cursor_1 loop
       print_report_results(r);
    end loop;

    for r in cursor_2 loop
       print_report_results(r);
    end loop;
    ...
end;

基本上,所有这些游标(超过3个)都是相同的摘要/报告查询.区别在于因子子查询.总有2个因子子查询“X”和“Y”,它们总是选择相同的列以提供给主报告查询.

问题是主报告查询非常大,大约70行.这本身并不是那么糟糕,但是它被复制粘贴到所有报告查询中(我认为有十几个).

因为唯一的区别在于因式子查询(并且它们都返回相同的列,它实际上只是它们选择的表和它们的条件的差异)我希望找到一种方法来重构所有这些以便有一个查询对于巨型报告和较小的报告用于各种因子子查询,以便在对报告的完成方式进行更改时,我只需要在一个地方进行,而不是十几个.更不用说更容易导航(和阅读)的文件了!

我只是不知道如何正确地重构这样的东西.我在考虑流水线功能?我不确定它们是否适合这种情况,或者如果有更简单的方法……

另一方面,我也想知道通过拆分报告查询是否会显着恶化性能.性能(速度)是该系统的一个问题.如果它增加了大量的执行时间,我宁愿不为开发人员的方便而引入更改.

我想我最终喜欢的是看起来像这样的东西(我只是不确定如何做到这一点,以便它实际编译):

cursor main_report_cursor (in_X,in_Y) is
    with X as (select * from in_X),Y as (select * from in_Y)
  /*main select*/
  select count(X.col1),...

cursor x_1 is
     select col1,col2 from TAB where col1 = '1';
cursor y_1 is
     select col1,col2 from TAB where col2 = '3'

...
begin
for r in main_report_cursor(x_1,y_1) loop
   print_report_results(r);
end loop;

for r in main_report_cursor(x_2,y_2) loop
   print_report_results(r);
end loop;
...

(使用Oracle 10g)

使用流水线功能.例如:
drop table my_tab;
create table my_tab
(
col1 number,col2 varchar2(10),col3 char(1)
);
insert into my_tab values (1,'One','X');
insert into my_tab values (1,'Y');
insert into my_tab values (2,'Two','X');
insert into my_tab values (2,'Y');
insert into my_tab values (3,'Three','X');
insert into my_tab values (4,'Four','Y');
commit;

-- define types
create or replace package refcur_pkg is
    --type people_tab is table of people%rowtype;
    type my_subquery_tab is table of my_tab%rowtype;
end refcur_pkg;

创建流水线功能

-- create pipelined function
create or replace function get_tab_data(p_cur_num in number,p_cur_type in char)
return REFCUR_PKG.my_subquery_tab pipelined
IS
    v_ret  REFCUR_PKG.my_subquery_tab;
begin
    if (p_cur_num = 1) then
        if (upper(p_cur_type) = 'X') then
            for rec in (select * from my_tab where col1=1 and col3='X')
            loop
                pipe row(rec);
            end loop;
        elsif (upper(p_cur_type) = 'Y') then
            for rec in (select * from my_tab where col1=1 and col3='Y')
            loop
                pipe row(rec);
            end loop;
        else
            return;
        end if;
    elsif (p_cur_num = 2) then
        if (upper(p_cur_type) = 'X') then
            for rec in (select * from my_tab where col1=2 and col3='X')
            loop
                pipe row(rec);
            end loop;
        elsif (upper(p_cur_type) = 'Y') then
            for rec in (select * from my_tab where col1=2 and col3='Y')
            loop
                pipe row(rec);
            end loop;
        else
            return;
        end if;
    end if;
    return;
end;

MAIN程序示例

-- main procedure/usage
declare

  cursor sel_cur1 is
    with X as (select * from table(get_tab_data(1,'x'))),Y as (select * from table(get_tab_data(1,'y')))
    select X.col1,Y.col2 from X,Y where X.col1 = Y.col1;

begin
    for rec in sel_cur1
    loop
        dbms_output.put_line(rec.col1 || ',' ||  rec.col2);
    end loop;
end;

所有各种子查询都缩减为对单个流水线函数调用,该函数确定要返回的行.

编辑:

要将所有需要的类型和函数组合成1个过程,并将变量用于子查询函数参数,我将添加以下示例:

create or replace procedure my_pipe
IS
    -- define types
    type my_subquery_tab is table of my_tab%rowtype;
    type ref_cur_t is ref cursor;
    v_ref_cur ref_cur_t; 

    -- define vars
    v_with_sql varchar2(4000);
    v_main_sql varchar2(32767);
    v_x1 number;
    v_x2 char;
    v_y1 number;
    v_y2 char;
    v_col1 my_tab.col1%type;
    v_col2 my_tab.col2%type;

    -- define local functions/procs
    function get_tab_data(p_cur_num in number,p_cur_type in char)
    return my_subquery_tab pipelined
    IS
        v_ret  my_subquery_tab;
    begin
        if (p_cur_num = 1) then
            if (upper(p_cur_type) = 'X') then
                for rec in (select * from my_tab where col1=1 and col3='X')
                loop
                    pipe row(rec);
                end loop;
            elsif (upper(p_cur_type) = 'Y') then
                for rec in (select * from my_tab where col1=1 and col3='Y')
                loop
                    pipe row(rec);
                end loop;
            else
                return;
            end if;
        elsif (p_cur_num = 2) then
            if (upper(p_cur_type) = 'X') then
                for rec in (select * from my_tab where col1=2 and col3='X')
                loop
                    pipe row(rec);
                end loop;
            elsif (upper(p_cur_type) = 'Y') then
                for rec in (select * from my_tab where col1=2 and col3='Y')
                loop
                    pipe row(rec);
                end loop;
            else
                return;
            end if;
        end if;
        return;
    end;

BEGIN
    ---------------------------------
    -- Setup sql for cursors
    ---------------------------------
    -- this will have different parameter values for subqueries
    v_with_sql := q'{
    with X as (select * from table(get_tab_data(:x1,:x2))),Y as (select * from table(get_tab_data(:y1,:y2)))
    }';
    -- this will stay the same for all cursors
    v_main_sql := q'{
    select X.col1,Y where X.col1 = Y.col1
    }';

    ---------------------------------
    -- set initial subquery parameters
    ---------------------------------
    v_x1 := 1;
    v_x2 := 'x';
    v_y1 := 1;
    v_y2 := 'y';
    open v_ref_cur for v_with_sql || v_main_sql using v_x1,v_x2,v_y1,v_y2;
    loop
        fetch v_ref_cur into v_col1,v_col2;
        exit when v_ref_cur%notfound;
        dbms_output.put_line(v_col1 || ',' ||  v_col2);
    end loop;
    close v_ref_cur;
    ---------------------------------
    -- change subquery parameters
    ---------------------------------
    v_x1 := 2;
    v_x2 := 'x';
    v_y1 := 2;
    v_y2 := 'y';
    open v_ref_cur for v_with_sql || v_main_sql using v_x1,' ||  v_col2);
    end loop;
    close v_ref_cur;
end;

请注意,现在的好处是,即使您有许多不同的游标,也只需要定义主查询和子查询sql一次.在那之后,你只是在改变变量.

干杯

原文链接:https://www.f2er.com/oracle/242109.html

猜你在找的Oracle相关文章