3

私のデータベースには、親 ID リンクを使用して保存されているツリーがあります。

テーブル内のデータのサンプルは次のとおりです。

ID | 名前 | 親ID
---+-------------+-----------
0 | ルート | ヌル
1 | ノード 1 | 0
2 | ノード 2 | 0
3 | ノード 1.1 | 1
4 | ノード 1.1.1 | 3
5 | ノード 1.1.2 | 3

ここで、特定のノードのすべての直接の子孫のリストを取得したいと考えていますが、存在しない場合は、ノード自体を返すだけにしたいと考えています。

id = 3 の子のクエリの戻り値を次のようにします。

子供
--------
4
5

次に、id = 4 の子のクエリは次のようになります。

子供
--------
4

ツリーをネストされたセットに格納する方法を変更できますが、それによって必要なクエリがどのように実現されるかわかりません。

4

2 に答える 2

6

新規では、 :PostgreSQL 8.4でそれを行うことができますCTE

WITH RECURSIVE q AS
        (
        SELECT  h, 1 AS level, ARRAY[id] AS breadcrumb
        FROM    t_hierarchy h
        WHERE   parent = 0
        UNION ALL
        SELECT  hi, q.level + 1 AS level, breadcrumb || id
        FROM    q
        JOIN    t_hierarchy hi
        ON      hi.parent = (q.h).id
        )
SELECT  REPEAT('  ', level) || (q.h).id,
        (q.h).parent,
        (q.h).value,
        level,
        breadcrumb::VARCHAR AS path
FROM    q
ORDER BY
        breadcrumb

詳細については、私のブログのこの記事を参照してください。

以前8.3は、関数を作成する必要があります。

CREATE TYPE tp_hierarchy AS (node t_hierarchy, level INT);

CREATE OR REPLACE FUNCTION fn_hierarchy_connect_by(INT, INT)
RETURNS SETOF tp_hierarchy
AS
$$
        SELECT  CASE
                WHEN node = 1 THEN
                        (t_hierarchy, $2)::tp_hierarchy
                ELSE
                        fn_hierarchy_connect_by((q.t_hierarchy).id, $2 + 1)
                END
        FROM    (
                SELECT  t_hierarchy, node
                FROM    (
                        SELECT  1 AS node
                        UNION ALL
                        SELECT  2
                        ) nodes,
                        t_hierarchy
                WHERE   parent = $1
                ORDER BY
                        id, node
                ) q;
$$
LANGUAGE 'sql';

この機能から選択します。

SELECT  *
FROM    fn_hierarchy_connect_by(4, 1)

最初のパラメータはルートidで、2番目のパラメータは。である必要があります1

詳細については、私のブログのこの記事を参照してください。

アップデート:

第1レベルの子のみ、または子が存在しない場合はノード自体を表示するには、次のクエリを発行します。

SELECT  *
FROM    t_hierarchy
WHERE   parent = @start
UNION ALL
SELECT  *
FROM    t_hierarchy
WHERE   id = @start
        AND NOT EXISTS
        (
        SELECT  NULL
        FROM    t_hierarchy
        WHERE   parent = @start
        )

2番目のクエリは最大で2つのインデックススキャンを実行するため、これはより効率的ですJOIN。最初のクエリは子が存在するかどうかを確認し、2番目のクエリは子が存在しない場合は親行を選択します。

于 2009-07-17T18:08:07.487 に答える
0

私が望んでいた方法で機能するクエリを見つけました。

SELECT * FROM
   ( SELECT id FROM t_tree WHERE name = '' ) AS i,
   t_tree g
どこ
  ( ( i.id = g.id ) AND
       存在しない (SELECT * FROM t_tree WHERE 親 ID = i.id) ) または
  ( ( i.id = g.parentid ) AND
       EXISTS ( SELECT * FROM t_tree WHERE 親 ID = i.id ) )
于 2009-07-17T21:06:30.823 に答える