计算由经理监督的员工

时间:2015-12-09 04:10:09

标签: sql oracle directed-acyclic-graphs

假设我有一个名为' Hierarchy'有两列:'经理'和'从属'

此表中的每个条目都显示了经理与其管理的员工之间的关系。 e.g:

manager              subordinate

CEO                  regional_director
CEO                  store_manager
regional_director    store_manager
store_manager        cashier

我的问题是如何获得每个经理的下属数量,无论是

明确定义,例如CEO是regional_director的经理(CEO - >区域主管)

OR

隐式定义,例如regional_director是收银员的经理

(regional_director - > store_manager - >收银员)。

表中数据条目的问题在于,虽然经理及其下属的下属之间的隐含关系应计入该人员管理的员工数量,但也可能是表中的一个条目,两者之间有明确的关系,不应计算两次。 e.g。

CEO --> regional_director

regional_director --> store_manager

**BUT ALSO**

CEO --> store_manager

另一只手

regional_director --> store_manager

store_manager --> cashier

**but there does NOT exist a relation:**

regional_director --> cashier

由于此查询将在JDBC中运行,因此可以使用java操作输出以获得所需的结果,但我更倾向于使用sql。

此示例的输出如下:

Employee             num_subordinates

CEO                  3
regional_director    2
store_manager        1

在考虑解决方案时,我意识到我的问题可以通过如下所示的有向无环图来建模:

enter image description here

顶点是员工,有向边是指'经理。

就图表而言,我相信我的问题将转化为:对于每个顶点v,从顶点v开始的任何长度的路径都可以到达多少个其他顶点。

顶点7将能够到达顶点8,9,11,2,10,因此它的值将为5

抱歉这么长的问题。

2 个答案:

答案 0 :(得分:2)

简单版本将是:

with tree (manager, subordinate) as (
select manager ,subordinate from hierarchy 
union all 
select t.manager, h.subordinate  from tree t
   join hierarchy h
   on t.subordinate = h.manager 
   ) select manager, count(distinct subordinate ) 
     from tree
     group by manager

可以通过删除下一个循环中已有的节点来改进它。但也可以通过 count 中使用的简单明确来实现。

以下是示例:SQL Fiddle

无限循环保护也可以改善。

with tree (manager, subordinate, path) as (
select manager ,subordinate, manager || '->' || subordinate from hierarchy 
union all 
select t.manager, h.subordinate, t.path || '->' || h.subordinate from tree t
   join hierarchy h
   on t.subordinate = h.manager   
   where instr(path, h.subordinate) = 0
     ) select manager , count(distinct subordinate)
     from tree
     group by manager

我们在这里使用路径,它表明我们在节点之间跳转。如果从属已经在路径上,则跳过它。

示例在这里:SQL Fiddle

答案 1 :(得分:1)

使用标准SQL非常接近的一种方法是使用一组适用于每个级别的语句(直接,间接级别1,间接级别2),并排除那些已经计算过的语句。 Here is an example直接和第一级案例:

-- count direct reports
-- count indirect-at-one-level-of-separation reports
--   excluding counted-elsewhere (direct) reports
select 1, manager, count(*)
from hierarchy
group by manager
union
select 2, h1.manager, count(*)
from hierarchy h1, hierarchy h2
where h1.subordinate=h2.manager
  and not exists (
    select i1.manager
    from hierarchy i1
    where i1.manager=h1.manager
      and i1.subordinate=h2.subordinate
    )
group by h1.manager
order by 2, 1

您需要添加条目。但随着水平的提高,这将变得非常混乱。 Oracle的connect by可能有所帮助 - 我还没试过。

我猜这是用Java做的工作,也许是使用set?