将父行连接到其子项

时间:2011-07-02 05:33:14

标签: sql postgresql

我有一个由父子映射组成的表。

E.g

my_table
-----+------+---------
  id | name | child_id
-----+------+---------
  a  |  A1  | b
  b  |  B1  | c
  b  |  B2  | c
  b  |  B3  | a
  c  |  C1  | d
  d  |  D1  | a
  d  |  D2  | b

我想'加入'它们以产生这个输出: (标有'< - '的行表示由于所述原因该行不应存在)

desired_table
-----+--------+----------+-------------
  id |  name  | child_id | visited_ids
-----+--------+----------+-------------
  a  | A1, B1 |    c     | {'a', 'b'}
  a  | A1, B2 |    c     | {'a', 'b'}
  a  | A1, B3 |    a     | {'a', 'b'}  <-- 'a' was visited
  b  | B1, C1 |    d     | {'b', 'c'}
  b  | B2, C1 |    d     | {'b', 'c'}
  b  | B3, A1 |    b     | {'b', 'a'}  <-- 'b' was visited
  c  | C1, D1 |    a     | {'c', 'd'}
  c  | C1, D2 |    b     | {'c', 'd'}
  d  | D1, A1 |    b     | {'d', 'a'}
  d  | D2, B1 |    c     | {'d', 'b'}
  d  | D2, B2 |    c     | {'d', 'b'}
  d  | D2, B3 |    a     | {'d', 'b'}

这个新表中的行将再次重复“连接”到my_table,以便产生此输出。 (标有'&lt; - '的行表示由于所述原因该行不应存在)

desired_table
-----+------------+----------+----------------
  id |    name    | child_id |   visited_ids
-----+------------+----------+----------------
  a  | A1, B1, C1 |    d     | {'a', 'b', 'c'}
  a  | A1, B2, C1 |    d     | {'a', 'b', 'c'}
  b  | B1, C1, D1 |    a     | {'b', 'c', 'd'}
  b  | B1, C1, D2 |    b     | {'b', 'c', 'd'}  <-- 'b' was visited
  b  | B2, C1, D1 |    a     | {'b', 'c', 'd'}
  b  | B2, C1, D2 |    b     | {'b', 'c', 'd'}  <-- 'b' was visited
  c  | C1, D1, D1 |    a     | {'c', 'd', 'd'}  <-- 'd' was visited
  c  | C1, D1, D2 |    b     | {'c', 'd', 'd'}  <-- 'd' was visited
  c  | C1, D2, B1 |    c     | {'c', 'd', 'b'}  <-- 'c' was visited
  c  | C1, D2, B2 |    c     | {'c', 'd', 'b'}  <-- 'c' was visited
  c  | C1, D2, B3 |    a     | {'c', 'd', 'b'}
  d  | D1, A1, B1 |    c     | {'d', 'a', 'b'}
  d  | D1, A1, B2 |    c     | {'d', 'a', 'b'}
  d  | D1, A1, B3 |    a     | {'d', 'a', 'b'}
  d  | D2, B1, C1 |    d     | {'d', 'b', 'c'}  <-- 'd' was visited
  d  | D2, B2, C1 |    d     | {'d', 'b', 'c'}  <-- 'd' was visited
  d  | D2, B3, A1 |    b     | {'d', 'b', 'a'}

......等等。 仍然可以“加入”的行将加入,直到他们没有更多的孩子。 无法再加入的行将保持不变。

2 个答案:

答案 0 :(得分:1)

你的例子的一个问题是,你有一个无限循环(a,A1,b) -> (b,B3,a) -> (a,A1,b),这有点难以察觉。

但是这(和peufeu的链接)应该让你开始:

WITH RECURSIVE hierarchy (id, names, child_id, path)
AS
(
   SELECT id, array[name], child_id, array[id] as path
   FROM mapping
   WHERE id = 'a'

   UNION ALL

   SELECT c.id, p.names||c.name, c.child_id, p.path||c.id
   FROM mapping c
   JOIN hierarchy p ON p.child_id = c.id AND NOT (p.path @> (p.path||c.id))
)
SELECT *
FROM hierarchy
ORDER BY 1

它不会像你想要的那样创建“visited_ids”列

答案 1 :(得分:0)

您的帖子完全符合WITH RECURSIVE查询:

http://www.postgresql.org/docs/current/static/queries-with.html