计算由经理监督的员工

counting employees supervised by a manager

假设我有一个名为 'Hierarchy' 的 table,其中包含两列:'manager' 和 'subordinate'

此 table 中的每个条目都显示了经理与其管理的员工之间的关系。例如:

manager              subordinate

CEO                  regional_director
CEO                  store_manager
regional_director    store_manager
store_manager        cashier

我的问题是如何获取每个经理的下属人数,是否

明确定义 例如CEO 是 regional_director 的经理(CEO --> 区域总监)

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

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

table 中数据条目的问题在于,虽然经理与其下属的下属之间的隐含关系 应该 计入该人的员工人数管理,table 中也可能有一个条目,两者之间有明确的关系,不应被计算两次。例如

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

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

其中顶点是员工,有向边表示 'manager of'。

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

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

抱歉问了这么长的问题。

一种非常接近的方法,使用标准 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 中完成工作的案例,也许使用了一组?

简单版本为:

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 中使用的简单 distinct 来实现。

这是示例: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

我们在这里使用 path 来显示节点之间的跳转。如果 subordinate 已经在路径上则跳过它。

样本在这里:SQL Fiddle