SQL(Oracle)中的递归计算

时间:2014-11-11 23:46:01

标签: sql oracle stored-procedures plsql oracle11g

我很难找到ETL的解决方案,将一些数据放到我的结果表中。我想我无法使用纯SQL实现这一点,并且由于循环需要使用PL-SQL。 sql专家可以帮助我朝着正确的方向前进,或者提供一些指导来解决这个问题吗?

以下是该方案: 表:TABLEA和TABLEB。

步骤:

  1. 通过A_CD对TABLEA中的记录进行分组,并对A_AMT FIELD进行SUM。 (假设A_FLAG对于任何A_CD总是相同的。)。让我们将分组的结果集称为TABLEA_GRP(这不是表,它是分组查询)。
  2. 从TABLEB中选择一行,如果B_FLG为'N',则选择TABLEA_GRP中A_FLG为'N'的所有行。如果B_FLG为'Y',则选择TABLEA_GRP中的所有行。
  3. 启动在步骤2中选取的行的第一个记录,计算所选行的TOTAL_AMT与ALL TOTAL_AMT的SUM的比率。将比率乘以B_AMT并将结果数量添加到行TOTAL_AMT并存储在RESULTING_AMT中。对步骤2中选取的所有行重复此计算。
  4. 重复步骤2和3,现在使用先前计算相同A_CD的RESULTING_AMT值中的起始TOTAL_AMT VALUE。
  5. 结果不需要保存_RATIO字段,它仅用于演示目的。你会怎么做?

    基本上我想从TABLEA和TABLEB中获取RESULTING_TABLE中的数据

    有人可以帮忙吗?非常感谢您提供任何指导。

    Table Design with sample data

    编辑:我添加了A_DATE和B_DATE以支持两个表之间的连接。为简单起见,您可以执行A.A_DATE = B.B_DATE,例如此基本连接:

    SELECT
      A.A_CD,
      SUM(A.A_AMT) AS TOTAL_AMT,
      A.A_FLAG,
      A.A_DATE,
      B.B_ID,
      B.B_AMT,
      B.B_FLAG
    FROM
      TABLEA A
    JOIN TABLEB B
    ON A.A_DATE = B.B_DATE
    GROUP BY
      A.A_CD,
      A.A_FLAG,
      A.A_DATE,
      B.B_ID,
      B.B_AMT,
      B.B_FLAG
    ;
    

    Resulting data of above join

1 个答案:

答案 0 :(得分:1)

好的,我想我已经有了解决方案。这些数字与你的数字有点不同,但我相当确定我的正在做你想要的。我们可以在第1步和第1步中完成所有工作。 2使用单个查询(main_sql)。必须使用递归语句(recur_sql)完成3和4。

with main_sql as (
    select  a.*,
            b.*,
            sum(a_amt) over (partition by b_id) as cd_amt,
            rank() over (partition by a_cd order by b_id) as rnk
    from   (select a_cd, a_flag, sum(a_amt) as a_amt
            from   tablea
            group  by a_cd, a_flag) a,
            tableb b
    where   a.a_flag = case when b.b_flag = 'Y' then a.a_flag else b.b_flag end
    order by b_id, a_cd
), 
recur_sql (a_cd, b_id, total_amt, cd_amt, resulting_ratio, resulting_amt, rnk) as (
    select m.a_cd, 
           m.b_id, 
           m.a_amt as total_amt, 
           m.cd_amt, m.a_amt / m.cd_amt as resulting_ratio, 
           m.a_amt + (m.a_amt / m.cd_amt * m.b_amt) as resulting_amt, 
           rnk
    from   main_sql m
    where  rnk = 1

    union all

    select m.a_cd, 
           m.b_id, 
           r.resulting_amt as total_amt, 
           m.cd_amt, 
           r.resulting_amt / m.cd_amt as resulting_ratio, 
           r.resulting_amt + (r.resulting_amt / m.cd_amt * m.b_amt) as resulting_amt,
           m.rnk
    from recur_sql r,
         main_sql m
    where m.rnk > 1
    and   r.a_cd = m.a_cd
    and   m.rnk - 1 = r.rnk

)
select a_cd, b_id, total_amt, resulting_ratio, resulting_amt
from   recur_sql
order by 2, 1

enter image description here