在 SQL 语句中查找递归和
Posted
技术标签:
【中文标题】在 SQL 语句中查找递归和【英文标题】:Finding recursive sum in SQL statement 【发布时间】:2013-05-08 20:51:30 【问题描述】:我有两个表 A 和 B,例如:
A (id, dep_id)
和 B (id, amount)
那些表中的数据是这样的
A B
id dep_id id amount
--- ------- ---- --------
1 2 1 100
2 3 2 200
3 NULL 3 300
4 NULL 4 400
表 A 中的 id
列包含表 B 的 id
。对于表 A 中的给定 id
,可能有一个 dep_id
包含表 B 的 id
。
要求是计算 B 中的条目及其所有相关条目的数量之和。这必须在一个 sql 查询中完成。我不能为此使用 PL/SQL 块。任何想法如何做到这一点。
例子:
sum(id=1) = 100(id=1,dep_id=2) + 200(id=2,dep_id=3) + 300(id=3) = 600
【问题讨论】:
有点困惑。这是等级制度吗? (id = 孩子,dep_id = 父母)?还是我需要更多的咖啡? 您需要一个支持WITH RECURSIVE
的数据库版本才能在一个查询中获得此信息。您可以使用吗?
@AndrewLazarus 分层查询自 Oracle 2 以来一直存在(我相信是 1978 年 :)
@VincentMalgrat:我自己使用 Postgres,所以不太了解 Oracle 的增强。无论如何,这是这种查询的必经之路。
Help calculating complex sum in hierarchical dataset 的可能重复项
【参考方案1】:
你可以使用CONNECT BY ROOT
建立一个依赖链接(hierarchical query),然后聚合:
SQL> SELECT ID, SUM(amount)
2 FROM (SELECT connect_by_root(a.id) ID, b.amount
3 FROM a
4 JOIN b ON a.id = b.id
5 START WITH a.ID = 1
6 CONNECT BY PRIOR a.dep_id = a.ID)
7 GROUP BY ID;
ID SUM(AMOUNT)
---------- -----------
1 600
其他解决方案可用于this SQL quiz on plsqlchallenge 上类似但稍微复杂一点的架构(例如id:1
需要 4xid:2
,每个需要 8xid:3
)。
【讨论】:
【参考方案2】:作为 Vincents 查询的替代方法,您可以使用:
select sum(b.amount)
from B b
where b.id in (
select a.id from A a start with a.id = 1 connect by a.id = prior a.dep_id
);
SQLFiddle:http://sqlfiddle.com/#!4/d7d1c/5
【讨论】:
【参考方案3】:这是一个方法 - 很酷的技巧(来自具有不同名称的架构 - 你必须调整)
select part_id, new_rec.quantity*sum(math_calc( math,2)) m, unit_of_measure
from ( SELECT rownum, level lvl, part_id, quantity, unit_of_measure
, connect_by_isleaf || sys_connect_by_path(quantity,'*') math
from assembly
start with parent_part_id = new_rec.part_id
connect by parent_part_id = prior part_id ) p
group by part_id, unit_of_measure
基本上——这部分
connect_by_isleaf || sys_connect_by_path(quantity,'*') math
将求和的数学方程制成一个字符串 - 然后由这部分解析和计算
new_rec.quantity*sum(math_calc( math,2)) m
【讨论】:
【参考方案4】:另一种选择,使用递归 CTE:
with recur (id, dep_id, amount)as
(
select A.id, A.dep_id, b.amount
from A
inner join B on A.id = b.id
union all
select recur.id, a.dep_id, b.amount
from recur
inner join A on recur.dep_id = a.id
inner join B on a.id = b.id
)
select id, sum(amount)
from recur
group by id
在这里查看工作小提琴:http://sqlfiddle.com/#!4/c1c83/2
【讨论】:
【参考方案5】:我们可以使用递归查询来做到这一点。我无权访问数据库,但这是粗略的想法。查询结果可能不准确,这是在 DB2 中,
With Ax as
(
SELECT ID, DEP_ID FROM A
UNION ALL
SELECT AX.ID, A.DEP_ID
FROM AX, A
WHERE AX.DEP_ID = A.ID
)
SELECT A.ID, SUM(AMOUNT)
FROM AX AS A JOIN B
ON A.ID = B.ID
1 的结果集在 AX 中可能看起来像,
1 2
2 3
1 NULL
2 3
3 NULL
4 NULL
【讨论】:
以上是关于在 SQL 语句中查找递归和的主要内容,如果未能解决你的问题,请参考以下文章