あなたはこのためrecursive CTEを使用することができます。
WITH RECURSIVE recCTE AS
(
/*Get all the true children to seed the recursive query*/
SELECT
id,
parent_id,
condition as initial_condition,
1 as depth,
CAST(id as varchar(50)) as path
FROM
table a
WHERE
a.id NOT IN (SELECT DISTINCT parent_id from table)
and a.condition = 'true'
UNION ALL
/*Recursive bit that refers back to itself. Find the parents*/
SELECT
b.id,
b.parent_id,
a.initial_condition,
depth + 1 as depth,
cast(path || '>' || b.id as varchar(50)) as path
FROM
recCTE a
INNER JOIN table b ON
a.parent_id = b.id
WHERE
/*avoid going too deep in case of cycling*/
depth <= 20
)
SELECT * FROM recCTE
再帰CTEは二つの部分を使用しています:
再帰種子:これは、UNIONクエリの最初の半分です。これで、「True」であるすべての子(IDがParent_IDでない)を特定します。
再帰的な用語:これはUNIONクエリの後半です。それはFROM句の中で自身(recCTE)を参照し、table
に再び参加します。 recCTE.parent_id(以前の反復parent_id)をテーブルのid
にリンクします。次に、その反復に必要なすべての情報を取得します。
私はほとんどの場合、この階層の他のノードは、我々はに到達するためにヒットでした再帰的な深さ(それはこのレコードを取得するためにかかりましたどのように多くの再帰)、そして一番下の子供から始まるパスを(追跡このレコード)。
私はウサギの穴をあまりにも遠くに通り過ぎることがないように、深さを使っています。イベントでは次のようなレコードを持っている:無限ループ(循環)最悪のシナリオは、それが深い20サイクルになった後、それが停止しますですが引き起こす
+----+-----------+
| id | parent_id |
+----+-----------+
| 1 | 5 |
| 5 | 7 |
| 7 | 1 |
+----+-----------+
を(1> 5> 7> 1> 5> 7> 1> 5> 7> 1> 5> 7> 1> 5> 7> 1> 5> 7> 1> 5)。サイクリングを停止するには、パスフィールドを使用するなど、他の方法があります(例:WHERE a.path NOT LIKE '%' || a.parent_id || '%'
)。
必要に応じて、最終的な選択肢が少し好きになるかもしれませんが、そこには95%の道があります。
うわー、本当にいい説明、私はこれで夢中になりました、私は再帰的なCTEについて少し読んで驚きです! あなたのおかげで、その日を完全に保存しました。私は自分のテーブルにクエリを適用し、うまくいきました:D –
素晴らしい!私はそれが箱の外であなたのために働いてうれしいです。 Recursive CTEの学習曲線は間違いありませんが、あなたの周りに頭を浮かべれば、彼らはツールボックスにとって完璧な意味合いと素晴らしいツールになります。 – JNevill