使用单个查询选择所有祖先

时间:2018-03-18 13:49:44

标签: sql postgresql

我在PostgreSQL中有下表,需要获得具有给定ID的所有人的祖先 还必须能够区分父亲和母亲的结果。

Person table - has about 1M rows, schema looks like this:
+-----+--------+--------+
| id  | father | mother |
+-----+--------+--------+
|   1 |      2 |      3 |
|   2 |      4 |      5 |
|   3 |      6 |      7 |
|   4 |      8 |      9 |
|   5 |     10 |     11 |
| ... |    ... |    ... |
| ... |    ... |    ... |
+-----+--------+--------+

目前我正在循环中进行查询,每个人获得一行。

是否可以在单个查询(或2个查询)中获取所有祖先?

查询id 2的示例结果:

+----+--------+--------+
| id | father | mother |
+----+--------+--------+
|  2 |      4 |      5 |
|  4 |      8 |      9 |
|  5 |     10 |     11 |
+----+--------+--------+

3 个答案:

答案 0 :(得分:2)

WITH recursive ParentOf (id, father, mother )
AS
(
-- Anchor query
    SELECT id, father, mother 
    FROM test
    WHERE id = ? -- e.g. 2
    UNION ALL
-- Recursive query
    SELECT t.id, t.father, t.mother
    FROM test t
    INNER JOIN ParentOf
    ON t.id = ParentOf.father OR t.id = ParentOf.mother
)
-- Statement that executes the CTE
SELECT id, father, mother 
FROM ParentOf;

答案 1 :(得分:0)

这是对问题的原始版本的回答。

为此目的,最简单的方法是将每个父项用一列删除。然后使用递归CTE来获取所有父母。

代码如下所示:

with recursive t as (
      select 1 as id, 2 as father, 3 as mother union all
      select 2, 4, 5 union all
      select 3, 6, 7 union all
      select 4, 8, 9 union all
      select 5, 10, 11
     ),
     parents as (
      select id, father as parent from t union all
      select id, mother from t
     ),
     cte as (
      select p.id, p.parent
      from parents p
      where id = 2  -- or whatever id you want
      union all
      select cte.id, p.parent
      from cte join
           parents p
           on cte.parent = p.id
     )
select *
from cte;

Here是一个SQL小提琴。

答案 2 :(得分:-1)

如果我说得对, 您可以使用JOIN或简单的IN()

对于IN,它将类似于:

SELECT 
    p.id, 
    p.father,
    p.mother 
FROM person p
WHERE 
p.id = 2
OR p.id IN (SELECT father FROM person WHERE id = 2)
OR p.id IN (SELECT mother FROM person WHERE id = 2)

这会给你:

| id | father | mother |
|----|--------|--------|
|  2 |      4 |      5 |
|  4 |      8 |      9 |
|  5 |     10 |     11 |

对于JOIN,您可以对列进行自我加入以将其与ID配对。就像这样:

SELECT 
      x.id as id, 
      x.father as father, 
      x.mother as mother
FROM person p
LEFT JOIN person x ON x.id = p.id OR x.id = p.father OR x.id = p.mother
WHERE 
  p.id = 2

这也会给你相同的结果。

从那里,您可以在WHERE子句下使用更多条件来获得正确的结果。

Fiddle Demo

相关问题