【问题标题】:Finding recursive sum in SQL statement在 SQL 语句中查找递归和
【发布时间】: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 的增强。无论如何,这是这种查询的必经之路。

标签: sql algorithm oracle recursion


【解决方案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
          

          【讨论】:

            猜你喜欢
            • 2018-03-12
            • 1970-01-01
            • 2023-04-05
            • 2013-07-06
            • 2016-10-30
            • 2010-10-30
            • 2010-09-23
            • 1970-01-01
            • 2023-04-01
            相关资源
            最近更新 更多