SQL(Oracle)中的递归计算
我很难找到将一些数据ETL到结果表中的解决方案。我认为我无法使用纯SQL实现这一点,并且由于循环,需要使用PL-SQL。sql专家能否帮助我走向正确的方向,或者提供一些解决这个问题的指针 以下是场景: 表:表A和表B 步骤:SQL(Oracle)中的递归计算,sql,oracle,stored-procedures,plsql,oracle11g,Sql,Oracle,Stored Procedures,Plsql,Oracle11g,我很难找到将一些数据ETL到结果表中的解决方案。我认为我无法使用纯SQL实现这一点,并且由于循环,需要使用PL-SQL。sql专家能否帮助我走向正确的方向,或者提供一些解决这个问题的指针 以下是场景: 表:表A和表B 步骤: 按光盘对表A中的记录进行分组,并对“金额”字段求和。(假设任何A_CD的A_标志始终相同。)。让我们以TABLEA\u GRP的形式调用分组结果集(这不是一个表,它是一个分组查询) 从表格B中选择一行,如果B_FLG为“N”,则选择表格a_GRP中a_FLG为“N”的所有行
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
;
好的,我想我找到了解决办法。这些数字与你的有点不同,但我相当肯定我的数字符合你的要求。我们可以使用单个查询(main_sql)在步骤1和2中完成所有操作。3和4必须使用递归语句(recur_sql)完成
我想澄清一下:我是否正确理解了步骤2?第二步的结果:谢谢你的回复!是的,您的理解是正确的。好的,您在步骤3中称哪些行为“first”和“selected”?selected:结果-如果B_FLG为“N”,则选择表A_GRP中A_FLG为“N”的所有行。如果B_FLG为“Y”,则选择表a_GRP中的所有行。第一:第一行“已选”。非常感谢!正是我需要的。感谢您花了这么多时间来完成这项工作。不过有一个问题-当TABLEA中有几百万行时,这个解决方案是否比在带有游标的存储过程中更有效?我无法测试这一点,因为我还没有原始数据。计算中有一个错误:得出的_比率基于分母中的总金额。因此,任何一组B_ID的总和都将为1,以得到_比率。在当前的解决方案中,它只考虑了main_sql中总的比率。我不太确定您将如何计算得到的_比率值。您是否能够发布正在使用的PL/SQL代码?就性能而言,很难说。这实际上取决于SQL引擎如何处理这种递归。我上面的代码本质上是只使用SQL的动态编程。与许多DP算法一样,通过缓存每个结果并使用计算下一次迭代,可以使用过程解决方案改进递归解决方案。我建议创建一个合成数据集,看看哪种方法更快。
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