2011-06-03 110 views
3

我有一个程序,有一个参数和一个游标。该光标给出的结果如下所示:如何在Oracle中组合结果集?

0100 | 0 
0130 | 1 
0200 | 2 
0230 | 0 
... 

第一列是静态时间码。第二列是某个特定日期某个时间段内预定了多少次的汇总。

这程序是:

PROCEDURE DAILYLOAD (datep IN DATE, results OUT SYS_REFCURSOR) 
    AS 
    BEGIN 
    Open results for 
     SELECT RUN_TIME_C, COUNT (SCH_RPT_I) 
    FROM ITS_SCH_RPT_RUN_TIME 
     LEFT OUTER JOIN 
      ITS_SCH_RPT 
     ON ( RUN_TIME_C = RUN_TIME1_C 
      OR RUN_TIME_C = RUN_TIME2_C 
      OR RUN_TIME_C = RUN_TIME3_C) 
    WHERE EXP_DATE_D IS NULL 
     OR datep < exp_date_d AND datep > start_date_d AND SUSPENDED_USER='N' 
      AND ( ((TO_CHAR (datep, 'D') = 1) AND RUN_SUNDAY_C = 'Y') 
       OR ((TO_CHAR (datep, 'D') = 2) AND RUN_MONDAY_C = 'Y') 
       OR ((TO_CHAR (datep, 'D') = 3) AND RUN_TUESDAY_C = 'Y') 
       OR ((TO_CHAR (datep, 'D') = 4) AND RUN_WEDNESDAY_C = 'Y') 
       OR ((TO_CHAR (datep, 'D') = 5) AND RUN_THURSDAY_C = 'Y') 
       OR ((TO_CHAR (datep, 'D') = 6) AND RUN_FRIDAY_C = 'Y') 
       OR ((TO_CHAR (datep, 'D') = 7) AND RUN_SATURDAY_C = 'Y')) 
GROUP BY RUN_TIME_C 
ORDER BY RUN_TIME_C; 
    END DAILYLOAD; 

我想几次不同的参数调用从包装过程这个过程让我能拿出每周负荷和月负荷。从概念上讲,这可以通过将各个结果集合在一起进行,例如union all,并按第一列对每个分组的第二列进行分组。

现在,我有这样的事情

Dailyload(datep, results1); 
Dailyload(datep + 1, results2); 
... 

OPEN results FOR 
    SELECT run_time_c, 
     SUM(rpt_option_i) 
    FROM SELECT * 
      FROM results1 
     UNION ALL 
     SELECT * 
      FROM results2 
     UNION ALL ... 
     GROUP BY run_time_c 
     ORDER BY run_time_c 

有没有一种方法可以让我在Oracle中这样做吗?使用批量收集获取看起来很有希望,但我没有看到将其用于我的特定场景的好方法。

+2

您需要发布正在执行繁重任务的查询 - 正在运行多次的查询。当你封装功能时,SQL不会表现的很好 - 它是基于SET的,不像Java/C#/等。性能很糟糕时,维护的便利性值得吗? – 2011-06-03 15:04:21

+0

请澄清一下:您是否想要 1)执行多个过程调用(每个过程调用不同的参数)并让Oracle合并结果。 2)使用多个参数执行单个过程,并在单个响应中获得这些结果的联合。 或 3)多次执行一个程序并得到一个组合结果集,你不关心它们在哪里结合? (如果是这样,请将您的开发语言添加到OP_) – 2011-06-03 15:09:38

+0

我添加了基础查询。我认为@CosCallis的第1项描述了我想要的。 – brantgurga 2011-06-03 15:55:08

回答

0

您可以将其作为一个联合来执行,包括标识该组的列。个人选择会或多或少地复制您的DailyLoad SP正在做的事情。

select foo.Mygroup, sum(foo.col1) 
    from 
(
select 'A' as MyGroup, col1 WHERE ... 
union all 
select 'B' as MyGroup, col1 WHERE ... 
union all 
select 'C' as MyGroup, col1 WHERE ... 
) as Foo 
group by MyGroup 

如果组的数量是事先不知道,你可以建立符合该基本结构的动态SQL语句。

如果组数太大以致动态语句太大,可以使用存储过程,将每次调用的结果与MyGroup列一起放入临时表中。然后你可以通过select语句发出你的组来对临时表。

0

如果过程的输出参数是引用游标,并且不能复制它在内部执行的操作,以便像OMG Ponies所建议的那样创建一个很好的单个基于集合的查询,this previous answer可能会有所帮助。您可以使用一个中间管道函数打开SYS_REFCURSOR结果到的东西,你可以把一个表:

create package p as 
    type tmp_rec_type is record (run_time_c varchar2(4), 
     rpt_option_i number); 
    type tmp_table_type is table of tmp_rec_type; 

    procedure dailyload(p_date in date, p_results out sys_refcursor); 
    function func(p_date in date) return tmp_table_type pipelined; 
    procedure sumload(p_start_date in date, p_results out sys_refcursor); 
end; 
/

create package body p as 
    /* Your existing procedure, which may be elsewhere */ 
    procedure dailyload(p_date in date, p_results out sys_refcursor) is 
    begin 
     open p_results for 
      select to_char(created, 'HH24MI') as run_time_c, 
       count(*) as rpt_option_i 
      from all_objects 
      where trunc(created) = trunc(p_date) 
      group by to_char(created, 'HH24MI'); 
    end; 

    /* Intermediate pipelined function */ 
    function func(p_date in date) return tmp_table_type pipelined is 
     tmp_cursor sys_refcursor; 
     tmp_rec tmp_rec_type; 
    begin 
     dailyload(p_date, tmp_cursor); 
     loop 
      fetch tmp_cursor into tmp_rec; 
      exit when tmp_cursor%notfound; 
      pipe row(tmp_rec); 
     end loop; 
    end; 

    /* Wrapper function to join the result sets together */ 
    procedure sumload(p_start_date in date, p_results out sys_refcursor) is 
    begin 
     open p_results for 
      select run_time_c, sum(rpt_option_i) from (
       select * from table(func(p_start_date)) 
       union all 
       select * from table(func(p_start_date + 1)) 
       union all 
       select * from table(func(p_start_date + 2)) 
      ) 
      group by run_time_c; 
    end; 
end; 
/

猜你的数据类型,并从随机桌上拿起数据只是作为一个例子,克劳斯的。若要从SQL * Plus或SQL Developer中称:

var results refcursor; 

exec p.sumload(to_date('01-Jun-11','DD-Mon-RR'), :results); 

print :results 
0

我没有对此进行测试的时候,但我相信这将工作:

  1. 修改你的存储过程,使SYS_REFCURSOR的IN OUT参数,而不仅仅是一个OUT。
  2. 在for/each循环中设置参数(无论您在哪种语言中工作...)
  3. 在循环中传递对同一个SYS_REFCURSOR的引用。
  4. 在sproc中创建一个本地SYS_REFCURSOR变量,以便像当前那样进行选择。
  5. 存储过程的内部合并本地和参数SYS_REFCURSOR

这应该建立自己的结果集。

如果你不想测试这个,我可以在周末为C#/ Oracle 10g构建一个测试用例来测试我的假设。

另一种选择,如果您是在11g中,将是一个流水线查询所讨论How to create Oracle stored procedure which can return specific entities as well all entity(看@ TBONE的回答和他提供的链接...)

0

可以使用Oracle全局临时表中积累并进一步处理数据。

它是内存结构,开销很小。