递归CTE - 获取后代(多对多关系)

时间:2017-12-12 19:30:31

标签: postgresql graph many-to-many common-table-expression recursive-query

我拥有的:

给定一个树(或更像是有向图),描述系统如何由其通用部分组成。现在让这个系统是例如人体和节点的身体部位。

graph of entries in a database in a many-to-many aggregation

因此,例如3可能是具有左叶和右叶(69)的肝脏,两者都有静脉(8 )(也可以在任何未指明的肝脏位置找到,因此8 - > 3),但也可以在舌头(5)中找到。肺部(7) - 位于胸部(4) - 也有一个右叶,等等......(当然,肝脏中没有肺,也是6 - > 7是合理的,所以这个例子并不是最好的,但是你得到它。)

所以我在这样的数据库中有这些数据:

table: part
+----+------------+   id is primary key
| id | name       |
+----+------------+
|  1 | head       |
|  2 | mouth      |
|  3 | liver      |
|  4 | chest      |
|  5 | tongue     |
|  6 | left lobe  |
|  7 | lung       |
|  8 | veins      |
|  9 | right lobe |
+----+------------+

table: partpart
+-------+---------+   part&cont is primary key
| part  | cont    |   part is foreign key for part.id
+-------+---------+   cont is foreign key for part.id
|   2   |    1    |
|   3   |    1    |
|   5   |    2    |
|   6   |    3    |
|   7   |    3    |
|   7   |    4    |
|   8   |    3    |
|   8   |    5    |
|   8   |    6    |
|   8   |    9    |
|   9   |    3    |
|   9   |    7    |
+-------+---------+

我想要实现的目标:

我想查询部分3中可以找到的所有部分,并期望得到这样的结果:

result of query
+-------+---------+
| part  | subpart |
+-------+---------+
|   3   |    6    |
|   3   |    7    |
|   3   |    8    |
|   3   |    9    |
|   6   |    8    |
|   7   |    9    |
|   9   |    8    |
+-------+---------+

我觉得以这种理想的格式获得结果是不可行的,将它作为一个类似的设置仍然很好,因为我的目的是为用户显示这样的数据:

3
├─ 6
│  └─ 8
├─ 7
│  └─ 9
│     └─ 8
├─ 8
└─ 9
   └─ 8

我是怎么做的:

WITH RECURSIVE tree AS (

  SELECT part.id as part, partpart.cont (..where to define subpart?)
  FROM part JOIN partpart
  ON part.id = partpart.part
  WHERE part.id = 3

  UNION ALL

  SELECT part.id, partpart.cont
  FROM (part JOIN partpart
  ON part.id = partpart.part
  ), tree
  WHERE partpart.cont = tree.part

)

SELECT part, subpart FROM tree

这是我能做的最接近的,但当然它不起作用。

1 个答案:

答案 0 :(得分:1)

问题解决了,这是我需要的查询,我希望它曾经帮助别人......

WITH RECURSIVE graph AS (
  SELECT
    p.id AS subpart,
    pp.cont AS part
  FROM part p JOIN partpart pp
  ON p.id = pp.part
  WHERE pp.cont = 3
  UNION ALL
  SELECT
    part.id,
    partpart.cont
  FROM (part JOIN partpart
  ON part.id = partpart.part
  ), graph WHERE partpart.cont = graph.subpart
)
SELECT part, subpart, FROM graph