これは、単純な再帰共通テーブル式(WITH RECURSIVE
)の典型的な使用法です。 )、PostgreSQL8.4以降で利用可能です。
ここに示されています:http://sqlfiddle.com/#!12 / 78e15 / 9
サンプルデータをSQLとして指定:
CREATE TABLE Table1
("ID1" text, "ID2" text)
;
INSERT INTO Table1
("ID1", "ID2")
VALUES
('vc1', 'vc2'),
('vc2', 'vc3'),
('vc3', 'vc4'),
('vc4', 'rc7')
;
あなたは書くことができます:
WITH RECURSIVE chain(from_id, to_id) AS (
SELECT NULL, 'vc2'
UNION
SELECT c.to_id, t."ID2"
FROM chain c
LEFT OUTER JOIN Table1 t ON (t."ID1" = to_id)
WHERE c.to_id IS NOT NULL
)
SELECT from_id FROM chain WHERE to_id IS NULL;
これは、チェーンを繰り返しウォークし、各行をchain
に追加します。 from-およびto-pointersとしてのテーブル。 'to'参照が存在しない行に遭遇すると、その行の'参照にnullを追加します。次の反復では、「to」参照がnullであり、行がゼロであることがわかります。これにより、反復が終了します。
次に、外部クエリは、存在しないto_idを持つことにより、チェーンの終わりであると判断された行を取得します。
再帰的なCTEに頭を悩ませるには、少し手間がかかります。理解しておくべき重要なことは次のとおりです。
-
これらは、最初のクエリの出力から始まり、「再帰部分」の出力(
UNION
の後のクエリ)と繰り返し結合します。 またはUNION ALL
)再帰部分が行を追加しなくなるまで。これで反復が停止します。 -
これらは実際には再帰的ではなく、より反復的ですが、再帰を使用する可能性のある種類のものには適しています。
つまり、基本的にはループでテーブルを作成していることになります。行を削除したり変更したりすることはできません。新しい行を追加するだけなので、通常、結果をフィルタリングして目的の結果行を取得する外部クエリが必要です。多くの場合、反復の状態を追跡したり、停止条件を制御したりするために使用する中間データを含む列を追加します。
フィルタリングされていない結果を確認するのに役立ちます。最終的な要約クエリを単純なSELECT * FROM chain
に置き換えると 生成されたテーブルを確認できます:
from_id | to_id
---------+-------
| vc2
vc2 | vc3
vc3 | vc4
vc4 | rc7
rc7 |
(5 rows)
最初の行は手動で追加された開始点の行で、検索する対象を指定します。この場合はvc2
でした。 。後続の各行は、UNION
によって追加されました LEFT OUTER JOIN
を実行するed再帰用語 前の結果に対して、前のto_id
とペアになる新しい行のセットを返します (現在はfrom_id
にあります 列)次のto_id
。 LEFT OUTER JOIN
の場合 一致しない場合、to_id
nullになり、次の呼び出しで行が返され、反復が終了します。
このクエリは最後ののみを追加しようとしないためです 毎回行、それは実際には各反復でかなりの作業を繰り返しています。これを回避するには、ゴードンのようなアプローチを使用する必要がありますが、入力テーブルをスキャンしたときに前の被写界深度をさらにフィルタリングして、最新の行のみを結合します。実際には、これは通常は必要ありませんが、非常に大きなデータセットや、適切なインデックスを作成できない場合に問題になる可能性があります。
詳細については、CTEに関するPostgreSQLのドキュメントをご覧ください。