层次结构和同行的递归查询

时间:2015-09-26 21:32:33

标签: sql postgresql recursion

我有一些看起来像这样的数据:

CREATE TABLE relations (
  group_member_id int not null,
  group_boss_id int not null);

INSERT INTO relations (group_member_id, group_boss_id)
VALUES (19, 21), (21, 21), (19, 20), (20, 20), (21, 22), (22, 22);

基本思想是一个小组成员可能在各种不同的小组中有各种不同的老板(例如19个分为两组,分别有老板21和20)。小组成员可能是他自己的老板(例如,20岁是20岁的老板)。

隐含,如果这些成员共享同一个boss,则该组成员与另一个组成员属于同一组。所以19和21属于同一组,因为他们共有21个作为老板,19个和20个属于同一组,因为他们共有20个作为老板,21个和22个属于同一组,因为他们共有22个作为老板。

对于每个群组成员,我想找到最大老板ID,不仅是与该群组成员明确关联的老板ID,还包括与该成员关联的所有老板ID其他隐式组成员及其组成员等。我试图实现的最终输出是:

group_member_id | largest_boss_id
        19           22
        20           22
        21           22
        22           22

我已经尝试过这种非递归编码而没有太多运气:我遇到的主要问题是从20到21,然后从21到22,并在每一步收集对等组成员

1 个答案:

答案 0 :(得分:2)

这可能是一个相当容易的查询,如果不是因为同伴成员问题(即成员#20因为成员#19作为同伴而拥有超级老板#22)。

简单的部分是递归查询membership,它构建所有直接关系,包括通过多层次的层次结构。但是,成员#20将成为超级老板,因为不考虑同伴关系。

所有同伴的超级老板都添加到UNION中,行membership CTE。对于每个成员,找到该成员为其所有成员的其他成员(SELECT过滤器中的子WHERE),然后找到所有成员的超级老板并与当前成员进行成对。 (是的,不容易解释......)。由于查询使用简单的UNION(而不是UNION ALL),因此会删除所有重复项。

最后,在主查询中,选择(成员,超级老板)对。

SELECT group_member_id, max(group_boss_id) AS uber_boss
FROM (
  -- Recursive query identifies all direct relationships
  WITH RECURSIVE membership AS (
    SELECT group_member_id, group_boss_id FROM relations
    UNION
    SELECT m.group_member_id, r.group_boss_id
    FROM membership m
    JOIN relations r ON r.group_member_id = m.group_boss_id
  )
  SELECT * FROM membership

  UNION

  -- Now need to find all uber bosses of peers
  SELECT m.group_member_id, uber_boss
  FROM membership m,
  LATERAL (
    SELECT group_member_id, max(group_boss_id) AS uber_boss
    FROM membership
    WHERE group_member_id IN (
      -- The below selects the peers
      SELECT group_member_id FROM membership WHERE group_boss_id = m.group_member_id)
    GROUP BY 1
    ) chief

) qry
GROUP BY group_member_id
ORDER BY group_member_id;

SQLFiddle