6

我知道答案似乎是根据这篇文章使用“WITH RECURSIVE”,但我就是不明白。

我有一张名为 的表people,还有一张名为 的表position_hierarchy。该people表有一个唯一的 iduperson_id和我们调用的位置 idpcn和一个enabled标志(因为当有人离开并被替换时,他们的替换得到相同的pcn)。有position_hierarchypcn,另一列reports_topcn层次结构中高于他们的人的列。我想要做的是给一个人,并在层次结构中uperson_id找到uperson_id他们之上的所有人,和/或给一个uperson_id人和另一个人uperson_id,并告诉第二个人是否有人对第一个有监督职位。

标明公司总裁是因为他们pcn和他们一样reports_to。(不是我的决定 - 我会使用 null reports_to

到目前为止我想出的是:

with recursive parents (uperson_id, pcn, reports_to) as
(
 select p1.uperson_id, ph1.pcn, ph1.reports_to
 from people p1
 join position_hierarchy ph1 on ph1.pcn = p1.pcn
 where reports_to != ph1.pcn and active_revoke_flag = '0'

 union all

 select p2.uperson_id, ph2.pcn, ph2.reports_to
 from people p2
 join position_hierarchy ph2 on p2.pcn = ph2.pcn
 join parents pp on pp.pcn = ph2.reports_to
)
select parents.* from parents where uperson_id = 'aaa3644';

但这会返回具有相同 uperson_id、pcn 和 reports_to 的 5 行(这似乎是正确的行数,但我想要主管的 uperson_id 在每个级别。我觉得我错过了一些非常基本的东西,我可能会打耳光当你告诉我我做错了什么时,我的头。

我做了什么

根据Erwin Brandstetter 的回答,我修复了一些问题(主要是因为我没有弄清楚该表在哪个表active_revoke_flag中)并提出:

with recursive p as (
    select pcn, reports_to
    from   position_hierarchy
    where  pcn = (SELECT pcn FROM people WHERE uperson_id = 'aaa3644')
    union all
    select ph2.pcn, ph2.reports_to
    from   p
    join   position_hierarchy ph2 ON ph2.pcn = p.reports_to AND
           p.pcn != p.reports_to
)
select p2.uperson_id, p2.active_revoke_flag, p.*
from   p
join   people p2 USING (pcn)
where  p2.active_revoke_flag = '0';
4

2 回答 2

4

我会尝试这种自下而上的方法,从感兴趣的人开始,然后逐步向上:

with recursive p as (
    select p1.uperson_id, p1.pcn, ph1.reports_to
    from   people p1
    join   position_hierarchy ph1 USING (pcn)
    where  ph1.active_revoke_flag = '0'
    and    p1.uperson_id = 'aaa3644'

    union all

    select p2.uperson_id, p2.pcn, ph2.reports_to
    from   p
    join   position_hierarchy ph2 ON ph2.pcn = p.reports_to
                                 AND ph2.active_revoke_flag = '0'
    join   people p2 ON p2.pcn = ph2.pcn
)
select * from p;

或者,更快,因为我们只加入person一次:

with recursive p as (
    select pcn, reports_to
    from   position_hierarchy
    where  active_revoke_flag = '0'
    and    pcn = (SELECT pcn FROM person WHERE uperson_id = 'aaa3644')

    union all

    select ph2.pcn, ph2.reports_to
    from   p
    join   position_hierarchy ph2 ON ph2.pcn = p.reports_to
                                 AND ph2.active_revoke_flag = '0'
)
select p2.uperson_id, p.*
from   p
join   people p2 USING (pcn); -- assuming pcn is unique in table person

顺便说一句:我确实发现您的重复设计pcn有些可疑。

于 2012-09-01T21:15:12.103 回答
-2

如果您知道最大树深度,则可以将其合并到单个查询中;否则,您需要阅读 Joe Chelko 并重组您的表格。

最大深度为 5 的单个查询可能如下所示(未经测试):

选择不同的 ph1.pcn
来自 position_hierarchy ph1
在 ph1.pcn = ph2.reports_to 上加入 position_hierarchy ph2
left join position_hierarchy ph3 on ph2.pcn = ph3.reports_to
在 p3.pcn = ph4.reports_to 上左连接 position_hierarchy ph4
left join position_hierarchy ph5 on ph4.pcn = ph5.reports_to
其中 ph2.pcn = @my_pcn
或 ph3.pcn = @my_pcn
或 ph4.pcn = @my_pcn
或 ph5.pcn = @my_pcn;

结果将是所有@my_pcn 上级的 pcn 列表。您还可以添加一些东西来测试公司总裁的边缘情况。

Chelko wrote the book on hierarchies in SQL, literally: http://books.google.ca/books/about/Joe_Celko_s_Trees_and_Hierarchies_in_SQL.html?id=Jy4e8SbYO6sC

于 2012-09-01T21:27:59.380 回答