计算由经理监督的员工
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
假设我有一个名为 '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