1

使用以下 PostgreSQL 9.2.2 表:

  id    | parent_id
--------+----------
 body   | null
 head   | body
 mouth  | head
 eye    | head
 tooth  | mouth
 tongue | mouth
 sclera | eye
 cornea | eye

我需要一个输出,其中列出了每个非父母子女的所有直接间接父母,例如:

tooth   mouth
tooth   head
tooth   body
tongue  mouth
tongue  head
tongue  body
sclera  eye
sclera  head
sclera  body
cornea  eye
cornea  head
cornea  body

我试过搜索,我的结果只显示了使用递归的单项查询,比如:

WITH RECURSIVE t AS ( 
SELECT  parent_id, id 
FROM    item_tree 
WHERE   child_id = id 
UNION ALL 
SELECT  it.parent_id, it.id
    FROM    item_tree it 
JOIN    t 
ON  it.child_id = t.parent_id
) 
SELECT  id, child_id 
FROM    t 

我可以在外部编写一个循环替换id每次,但它只能在 SQL 中完成吗?

@丹尼尔,

这是原始查询的输出:

  id     parent_id
  ------ ---------
  cornea eye
  cornea NULL
  cornea head
  cornea body
  sclera eye
  sclera head
  sclera NULL
  sclera body
  tongue body
  tongue head
  tongue NULL
  tongue mouth
  tooth  body
  tooth  head
  tooth  mouth
  tooth  NULL 

然而,如果你用一个空过滤的 select 语句将它括起来,即使你删除了内部的空过滤器,它也会提供所需的内容,如下所示:

  select * from (
     WITH RECURSIVE t(id,parent_id) AS ( 
     select id,parent_id from item_tree i
     UNION ALL
     select t.id,i.parent_id from item_tree i JOIN t on i.id=t.parent_id 
     )
     select * from t order by id
  ) t1 where parent_id is not null;

无论如何,我已经点击了复选标记,因为这可能是一个错误(我已经尝试通过 jdbc 和在 pgAdmin3 中使用相同的输出运行这两个查询)

4

1 回答 1

0

假设表的结构是item_tree ( idtext, text ),递归查询可以从定义它们的叶子元素开始(即,它们不是任何东西的父元素),并且必须过滤parent_id具有 null 的顶级元素,parent_id也:

select id,parent_id from item_tree i
 where parent_id is not null and
  id not in  (select parent_id from item_tree where parent_id is not null)

然后将 (parent_id,id) 关系爬到树的顶部。

完整查询:

WITH RECURSIVE t(id,parent_id) AS ( 
select id,parent_id from item_tree i where parent_id is not null 
   and id not in  (select parent_id from item_tree where parent_id is not null)
UNION ALL
 select t.id,i.parent_id from item_tree i JOIN t on i.id=t.parent_id 
)
select * from t order by id;

编辑:上面的查询在其输出中包括层次结构顶部的 NULL。为了排除它们,可以改用这个修改后的版本。最终结果应该与带有外部过滤的已编辑问题中的查询相同。

WITH RECURSIVE t(id,parent_id) AS ( 
select id,parent_id from item_tree i where parent_id is not null 
   and id not in  (select parent_id from item_tree where parent_id is not null)
UNION ALL
 select t.id,i.parent_id from item_tree i JOIN t on i.id=t.parent_id
   where i.parent_id is not null 
)
select * from t order by id;
于 2013-01-04T19:59:35.313 回答