查询以显示每个人的所有较低级别的人员的所有收入的总和

时间:2014-11-15 15:38:57

标签: sql oracle hierarchical-data



我有一个包含表人员和收入的Oracle数据库。每个人都有一些领导者,很多人都可以拥有同一个领导者。领导者也可以拥有自己的领导者。所以有层次结构。这是我现在有的查询示例

http://sqlfiddle.com/#!4/15e85/3

我需要创建一个查询,计算每个人的所有下属(在所有较低级别的层次结构中)的收入总和。因此,主要领导者的总和将是除收入之外的所有收入的总和。怎么做到这一点?

1 个答案:

答案 0 :(得分:2)

SELECT p.root, sum(e.EARNINGVALUE) s 
FROM Earnings e JOIN
(SELECT p.IdPerson,
        connect_by_root p.IdPerson root,
        connect_by_isleaf lf
 FROM People p
 CONNECT BY PRIOR p.IdPerson= p.IdLeader
) p on p.IdPerson = e.IdPerson
where root != p.IdPerson
        -- uncomment this if you want to calculate earnings of people who don't have subordinates 
        -- or lf = 1
GROUP BY root;
  

如果当前行是a CONNECT_BY_ISLEAF 伪列,则返回1   CONNECT BY条件定义的树的叶子。否则它   返回0.此信息指示给定行是否可以   进一步扩展以显示更多的层次结构。

     

CONNECT_BY_ROOT 是一元运算符,仅在分层查询中有效。使用此运算符限定列时,   Oracle使用根行中的数据返回列值。这个   operator扩展了CONNECT BY [PRIOR]条件的功能   分层查询。

     

Oracle按如下方式处理分层查询:

     
      
  • 首先评估连接(如果存在),无论是在FROM子句中还是在WHERE子句谓词中指定了连接。

  •   
  • 评估CONNECT BY条件。

  •   
  • 评估剩余的WHERE子句谓词。

  •   

如果您没有指定START WITH Oracle以每行开头。因此,对于每一行,您都可以找到其下属的收入。

这是没有CONNECT_BY_ROOT的版本:

with tmp_tree as (
  SELECT p.IdPerson, rownum rw, level lvl
  FROM People p
  CONNECT BY PRIOR p.IdPerson = p.IdLeader
),
tmp_tree_with_root as (
  SELECT t1.IdPerson, t2.IdPerson root
  FROM (SELECT IdPerson, min(rw) over(partition by root_group) root_rw
          FROM (SELECT IdPerson, rw, 
                       rw - sum(case when lvl > 1 then 1 else 0 end) 
                            over(order by rw) root_group
                FROM tmp_tree) 
        ) t1
        join tmp_tree t2
        on t1.root_rw = t2.rw
) 
SELECT p.root, sum(e.EARNINGVALUE) s 
FROM Earnings e JOIN tmp_tree_with_root p
     on p.IdPerson = e.IdPerson
where root != p.IdPerson
GROUP BY root;

1)使用rownum标记层次结构中的每一行
2)使用分析rw - sum(case when lvl > 1 then 1 else 0 end) over(order by rw)来定义组(每个组是一个层次结构)
3)tmp_tree_with_root给出与带有CONNECT_BY_ROOT

的子查询相同的结果