2017-08-31 8 views
0

ブレッドクラム/ツリーパスを取得するには、再帰的なCTEを使用することができますが、ブレッドクラム/ツリーを知っているアイテムを選択することは可能ですか?例えばブレッドクラム/ツリーパスからアイテムを取得する(隣接モデル)

id| name | parent_id 
-------------------- 
0 | a | null 
1 | b | 0 
2 | c | 1 
3 | b | 2 

ブレッドクラムは、このように見えた場合、A/B/C/B、どのように、ID 3がこの情報を知ることで行を返すことができるだろうか?

+0

ブレッドクラムの最後の部分を検索します(名前が一意の場合のみ)。 'SELECT * FROM tab where name =(最後の部分を得るためにsql文字列func)' – lad2025

+0

名前は一意ではありません。主キーIDのみ – jouerai

答えて

1

Postgres just rocks。

http://sqlfiddle.com/#!17/0a6f4/27

アイデアは、ルートからノードの数を表し、「レベル」とともに、ツリー内の各要素のパスを返す教科書再帰クエリを構築することです。 「深さ」と呼ぶこともできます。

次に、パス 'a/b/c/b'をARRAY ['a'、 'b'、 'c'、 'b'] ...に変換します。各レベルで探しているノードの名前を返します。

WITH RECURSIVE h(id,name,parent_id,level,path,search_path) AS (
    SELECT id, 
     name, 
     parent_id, 
     1, 
     ARRAY[name], 
     ARRAY['a','b','c','b'] 
    FROM t WHERE parent_id IS NULL AND name = 'a' 
    UNION ALL 
    SELECT t.id, 
     t.name, 
     t.parent_id, 
     level+1, 
     path || t.name, 
     h.search_path 
    FROM t JOIN h ON(t.parent_id=h.id) 
     WHERE search_path[level+1] = t.name 
) 
SELECT *, path=search_path as match FROM h; 

これは、要求されたパスからパス順にノードを返します。要求された行が見つかったときに真となる「一致」列を追加しました。この行だけを必要とする場合は、最も近い一致で停止し、パスが見つからない場合にそれを戻す場合を除き、条件をwhereに入れます。その場合は、最後の行を取る必要があります。

Funnily十分に、mysqlは配列変数を使ってparent_idを一つの行から次の行に転送することができますが、MySQLには配列がありませんので、find_in_set()の代わりに...働くことができますハックの種類...

関連する問題