1

次のPostgreSQL9.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を使用した単一アイテムのクエリのみが表示されました。

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 

ただし、次のように、内部のnullフィルタを削除した場合でも、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_treeidtext、parent_idtext)であるとすると、再帰クエリは、リーフ要素を定義するときに(つまり、何の親でもない)リーフ要素から開始でき、nullparent_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 に答える