oracle 递归计算,SQL中的递归计算(Oracle)

我很难找到一种解决方案,可以将一些数据ETL到结果表中。我认为我无法使用纯SQL来完成此操作,并且由于循环需要使用PL-SQL。 sql专家可以帮助我朝正确的方向发展还是提供一些解决此问题的指针?

这是场景:

表格:TABLEA和TABLEB。

脚步:

通过A_CD对TABLEA中的记录进行分组,并对A_AMT FIELD求和。 (假设A_FLAG对于任何A_CD总是相同的。)让我们将分组结果集称为TABLEA_GRP(这不是表,而是分组查询)。

从TABLEB中选择一行,如果B_FLG为'N',则在TABLEA_GRP中选择所有行,其中A_FLG为'N'。如果B_FLG为'Y',则选择TABLEA_GRP中的所有行。

从第2步中选择的行的第一条记录开始,计算所选行的TOTAL_AMT与SUM之和为TOTAL_AMT的比率。将比率乘以B_AMT,然后将所得金额添加到TOTAL_AMT行中,并存储在RESULTING_AMT中。对在步骤2中选择的所有行重复此计算。

重复步骤2和3,现在使用从相同A_CD的先前计算得出的RESULTING_AMT值开始的TOTAL_AMT VALUE。

RESULTING _RATIO字段无需保存,仅用于演示目的。你会怎么做?

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

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

7032bc66d4cbe4f75375c7e8f51acf3a.png

编辑:我添加了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

;

1d0aac679dd1a9c0e4fd4b369708b3fb.png

只是为了澄清一下:我是否正确理解步骤2? 我的步骤2的结果:sqlfiddle.com/#!4/c7670/2/0

谢谢回复! 是的,您的理解是正确的。

好的,您在第3步中将哪一行称为"第一"和"选定"?

已选择:结果-如果B_FLG为N,则选择TABLEA_GRP中的所有行,其中A_FLG为N。如果B_FLG为Y,则选择TABLEA_GRP中的所有行。 第一:选定的第一行。

好吧,我想我已经找到了解决方案。 这些数字与您的数字有些不同,但是我很确定我在做什么。 我们可以使用单个查询(main_sql)完成步骤1和2中的所有操作。 3和4必须使用递归语句(recur_sql)完成。

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

f653ffcdb28ddc0a833014876f698d2b.png

非常感谢!正是我所需要的。感激您花费的时间。

但是,有一个问题-当TABLEA中有几百万行时,此解决方案是否比在具有游标的存储过程中进行处理更有效?由于我还没有原始数据,因此无法测试。

计算中的一种错字:RESULTING_RATIO基于分母中的TOTAL_AMT总和。因此,任何B_ID组的RESULTING_RATIO总和为1。在当前解决方案中,它仅考虑main_sql中占总数的比率。

我不太确定您还将如何计算result_ratio值。您可以发布正在使用的PL / SQL代码吗?在性能方面,很难说。这实际上取决于SQL引擎如何处理这种递归。我上面的代码本质上是仅使用SQL的动态编程。与许多DP算法一样,可以通过缓存每个结果并用于计算下一个迭代来使用过程解决方案来改进递归解决方案。我建议创建一个综合数据集,看看哪种方法更快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值