【问题标题】:How to have a stored procedure do this all in one stored procedure instead of two separate ones如何让一个存储过程在一个存储过程中而不是两个单独的存储过程中完成这一切
【发布时间】:2018-10-03 16:51:25
【问题描述】:

所以我试图按小时将聚合(求和)值插入到值表中。按小时插入值后,我想在同一过程中按天插入综合总和。有没有办法让存储过程按小时完成插入,然后通过对“每小时”过程中刚刚插入的数据求和来绘制游标?我是否需要提交第一个事务,然后不久再创建另一个游标?

以下是一些示例数据:

已经按小时求和/聚合的查询结果:

SUM (VALUE_TX)   UTC_OFFSET   DATA_DATE    HR
   5              8           902018      1
  10              8           902018      2
   4              8           902018      3

在将上面的第一个结果集插入到表中之后,我想要插入的内容。我将从我将要插入的同一个表中提取这些值。

SUM (VALUE_TX)   UTC_OFFSET   DATA_DATE    HR
   19                8           902018    null

我正在考虑执行以下操作,但我不确定这是否是最好的方法。我打算按 data_Date 分组以形成第二个游标。

Create or replace procedure AGG_HOURLY_DAILY IS
CURSOR c1 is
Select sum(value_Tx) as sum_of_values
     , utc_offset
     , data_date
     , hr
  from value
 group by data_date, utc_offset, hr
where HR is not null;
l_var c1%ROWTYPE;
CURSOR c2 is
Select sum(value_tx)
     , utc_offset
     , data_date
     , hr
 group by data_date, utc_offset, hr
Where HR is null;
k_var c2%rowtype;
BEGIN
Open C1;
LOOP;
  FETCH c1 into l_var;
 EXIT WHEN c1%NOTFOUND;
  Insert into value(value_id, value_tx, utc_offset, data_date, hr)
             values(null, l_var.sum_of_values, l_var.utc_offset, l_var.data_date, l_var.hr);
END LOOP;
CLOSE C1;
OPEN C2;
LOOP;
  FETCH c2 into k_var;
 EXIT WHEN c2%NOTFOUND;
  Insert into value(value_id, value_tx, utc_offset, data_date, hr)
             values(null, l_var.sum_of_values, l_var.utc_offset, l_var.data_date, l_var.hr);
END LOOP;
Close c1;
Close c2;
END AGG_HOURLY_DAILY;

注意:Value_ID 由我创建的序列/触发器自动生成

【问题讨论】:

  • 我相信 ORACLE 支持 GROUP BY ROLLUP 子句,因此您可以通过一个查询完成整个操作,而无需游标。如果您将第一个查询放入公共表表达式中,那么让您的第二个查询引用您应该能够访问所需数据集的 CTE。
  • @DavePoole 你能给我看一个简单的例子吗? (对不起)
  • 另外,如果我没有游标,如何在不使用循环的情况下将整个结果集加载到表中?

标签: oracle plsql


【解决方案1】:

也许你想要这样的东西:

with demo (value_tx, utc_offset, data_date, hr)
as   ( select 1, 8, '902018', 1 from dual union all
       select 2, 8, '902018', 1 from dual union all
       select 2, 8, '902018', 1 from dual union all
       select 4, 8, '902018', 2 from dual union all
       select 6, 8, '902018', 2 from dual union all
       select 1, 8, '902018', 3 from dual union all
       select 2, 8, '902018', 3 from dual union all
       select 1, 8, '902018', 3 from dual )
select sum(value_tx), utc_offset, data_date, hr
from   demo
group by grouping sets ((utc_offset, data_date, hr), (utc_offset, data_date))
order by hr nulls last;

SUM(VALUE_TX) UTC_OFFSET DATA_DATE         HR
------------- ---------- --------- ----------
            5          8 902018             1
           10          8 902018             2
            4          8 902018             3
           19          8 902018    

GROUPING SETS 子句本质上是说您需要两个 GROUP BY 操作:一个在 (utc_offset, data_date, hr) 上,一个在 (utc_offset, data_date) 上。

Read more in the documentation.

【讨论】:

    【解决方案2】:

    第一步,用简单的INSERT ... SELECT语句替换游标:

      Insert into value( value_tx, utc_offset, data_date, hr)
      SELECT sum(value_Tx) as sum_of_values
         , utc_offset
         , data_date
         , hr
      from value
     group by data_date, utc_offset, hr
    where HR is not null;
    
    Insert into value( value_tx, utc_offset, data_date, hr)
    Select sum(value_tx)
         , utc_offset
         , data_date
         , hr
     group by data_date, utc_offset, hr
    Where HR is null;
    

    由于这种简化,很容易看出这两个查询仅在一个元素上有所不同:HR is NULLHR is NOT NULL。 所以上面两个插入两行的查询可以简化为一个插入同样两行的查询:

    Insert into value( value_tx, utc_offset, data_date, hr)
    SELECT sum_tx, utc_offset, data_date, hr
    FROM (
       Select CASE WHEN hr IS NULL THEN 1 ELSE 2 END as xxx
                , sum(value_tx) as sum_tx
                , utc_offset
                , data_date
                , hr
       group by CASE WHEN hr IS NULL THEN 1 ELSE 2 END,
             data_date, utc_offset, hr
    )
    ;
    

    所以我不需要 PL/SQL 吗?有没有办法我可以做到这一点 使用 PL/SQL?

    您可以在程序中执行此操作,也可以在没有程序的情况下执行此操作。
    如果你想有一个程序,只需这样做:

    Create or replace procedure AGG_HOURLY_DAILY IS
    BEGIN
      Insert into value( value_tx, utc_offset, data_date, hr)
      SELECT sum_tx, utc_offset, data_date, hr
        FROM (
           Select CASE WHEN hr IS NULL THEN 1 ELSE 2 END as xxx
                    , sum(value_tx) as sum_tx
                    , utc_offset
                    , data_date
                    , hr
           group by CASE WHEN hr IS NULL THEN 1 ELSE 2 END,
                 data_date, utc_offset, hr
        )
        ;
    END;
    /
    

    【讨论】:

    • 所以我不需要 PL/SQL 吗?有没有办法通过使用 PL/SQL 来做到这一点?我问的原因是因为这只是我正在尝试做的简化版本。实际上,我正在抓取一堆数据并插入到 3-4 个不同的表中......
    • 这是在程序中完成的,非常简单——我已经更新了一个例子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 2010-11-14
    • 1970-01-01
    • 2014-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多