1.はじめに
階層関係がある場合、通常、親ノードを示すようにテーブル構造を設計するときに、parent_idフィールドが追加されます。
ツリーテーブルのクエリは通常のテーブルとは異なります。ほとんどの場合、親ノードのデータをクエリすると、その子ノードに再帰的にクエリを実行する必要があります。また、親ノードを削除すると、子ノードも再帰的に削除する必要があります。
SQLステートメントの制限により、関数またはストアドプロシージャでない限り、再帰ステートメントを直接記述することはできません。
POSTGREデータベースエンジンは、上記の問題を解決するためにWITHRECURSIVEを提供します。
詳細については、公式情報を参照してください:https://www.postgresql.org/docs/current/queries-with.html
たとえば、次のツリー構造:
二、WITH
WITHは、より大きなクエリで使用するための補助ステートメントを作成する方法を提供します。
これらのステートメントは通常、共通テーブル式(commontableexpression)またはcteと呼ばれます。
これは、1つのクエリに対してのみ存在する一時テーブルを定義するものと考えることができます。
WITH句の各補助ステートメントは、SELECT、INSERT、UPDATE、またはDELETEにすることができます。
WITH句自体がメインステートメントに付加されます。メインステートメントは、SELECT、INSERT、UPDATE、またはDELETEにすることもできます。
たとえば、次のSQLステートメント:
T as( select * from template_info where parent_id = -1 )select * from T
すべての第1レベルのノードが照会され、括弧内のステートメントによって検出された内容が一時テーブルTに格納されてから、すべてがTから照会されます。
複数のWITH句をコンマで区切って定義できるため、複数のテーブルをクエリし、並行してクエリを実行してから、一時テーブルのコレクションをクエリできます。
3、リカーシブ
オプションのRECURSIVE再帰修飾子は、単純な構文から、標準SQLでは不可能なことを実行できる機能に変更されました。
再帰を使用すると、WITHクエリは独自の出力を参照できます。
with RECURSIVE t as (select * from template_info where id = 18 union all (selectd。* from t inner join template_info d on t.id = d.parent_id) )select * from t
クエリのロジックは次のとおりです。
1.非再帰的な項目を計算します。つまり、select * from template_info where id = 18です。この行はルートノードを見つけ、その結果を一時テーブルBに格納します。
2.再帰項を計算します。つまり、t.id = d.parent_idのt内部結合template_infodからd。*を選択し、一時テーブルBとtemplate_infoを結合してCを取得し、BCをマージしてDを取得します。
3.すべてのCが空になるまで再帰項目を計算し、結果セットをマージして、反復プロセスを終了します。
4.結果セットをクエリして、最終結果を取得します。
注:厳密に言えば、このプロセスは再帰的ではなく反復的ですが、再帰はSQL標準委員会によって選択された用語です。
さらに分解する手順:
1.クエリ1
select * from template_info where id = 18
2.合併
with RECURSIVE t as (select * from template_info where id = 18 union (selectd。* from t inner join template_info d on t.id = d.parent_id where t.id = 18) )select * from t
3.再マージ
with RECURSIVE t as (select * from template_info where id = 18 union (selectd。* from t inner join template_info d on t.id = d.parent_id where t.id = 18) )select * from t union( with RECURSIVE t2 as ( (selectd。* from t inner join template_info d on t.id = d.parent_id where t.id = 19) )select * from t2 )
4.再度マージします。これ以上、クエリを終了しません。
with RECURSIVE t as (select * from template_info where id = 18 union (selectd。* from t inner join template_info d on t.id = d.parent_id where t.id = 18) )select * from t union( with RECURSIVE t2 as ( (selectd。* from t inner join template_info d on t.id = d.parent_id where t.id = 20) )select * from t2 )
第四に、WITH
更新中
WITH t AS( UPDATE製品SET価格=価格* 1.05 返品* ) SELECT * FROM t;
5、WITHでのDELETEとINSERT
このクエリは実際にproducts
は行からに移動しますproducts_log
。からの指定された行WITH
のDELETE
削除products
、
RETURNING
句でコンテンツを返すと、メインクエリが出力を読み取り、挿入しproducts_log
ます。
WITHmoved_rows AS( DELETE FROM products WHERE "date"> = '2010-10-01' AND "date" <'2010-11-01' RETURNING * ) INSERT INTO products_log SELECT * FROMmoved_rows;