PostgreSQLの再帰クエリは、再帰的な要約を使用します

RECURSIVE

序文

WITHは、大規模な照会に使用される補助文を書くための方法を提供します。これらの記述は、通常、一時テーブルのみクエリに存在するように定義することができる共通テーブル式またはCTEを、と呼ばれています。句各補助ステートメントはSELECT、INSERT、UPDATE、DELETE、またはすることができ、WITH句自体もメイン書に取り付けることができる、ステートメントがメインSELECT、INSERT、UPDATEまたはDELETEであってもよいです。

CTEまたはWITH

文のWITH一般的に共通テーブル式(共通テーブル式)またはCTEを言及しました。

セカンダリマスタステートメントとして添付声明、WITHステートメントとメイン文は、任意のステートメントSELECT、INSERT、UPDATE、DELETEであってもよい。WITH

栗のために

WITH result AS (
    SELECT d.user_id
    FROM documents d
    GROUP BY d.user_id
),info as(
    SELECT t.*,json_build_object('id', ur.id, 'name', ur.name) AS user_info
    FROM result t
    LEFT JOIN users ur on ur.id = t.user_id
    WHERE ur.id IS NOT NULL
)select * from info

WITHは、二つの補助文、結果や情報を定義します。クエリ結果の情報は、ユーザの要件を満たし、その後、この情報に情報を組み立てるために、データは、私たちが必要とする情報を組み立てました。

もちろん、これは不可能ですが、主なものは、CTEデータフィルタリングを行うことです。その平均値を何、我々は、マルチレベルのCTE、組立クエリフィルタのその後の層が定義することができます。私たちが必要とするデータアウト最終フィルタは、もちろん、あなたは、すべてのデータのうち、なぜないものを頼むかもしれないデータが大きい場合には、もちろん、我々は、マルチレベルのデータによってアセンブリフィルタリングするだけでなく、優れた効率インチ

WITHデータ変更ステートメントを使用します

DELETE、UPDATE、INSERT文を使用している間WITHは、SELECT文で使用することはできません。したがって、WITHを使用する次の例では、SQL文の中でさまざまな操作を行うことが可能です。

WITH moved_rows AS (
  DELETE FROM products
  WHERE
    "date" >= '2010-10-01'
  AND "date" < '2010-11-01'
  RETURNING *
)
INSERT INTO products_log
SELECT * FROM moved_rows;

削除された財別RETURNING句は、データセットによって削除CTEのmoved_rows、最後にメインのINSERT文がproducts_logに挿入された月のテーブルデータから製品、および譲受人WITH DELETE文で、本実施形態を削除します。

あなたはWITH SELECT文の内部で使用されていない、とRETURNING句によって結果セットを返さなかった場合は、メインクエリは、CTEを参照することはできませんが、メインクエリとWITH文はまだ続けることができます。この状況は、WITH文を達成し、次の例では、トランザクションを明示的に使用せずにトランザクションの主な発言を確保するために、SQL文の中で無関係な文の複数で達成することができます。

WITH d AS (
  DELETE FROM foo
),
u as (
  UPDATE foo SET a = 1
  WHERE b = 2
)
DELETE FROM bar;

Subステートメントの子ビーイングと他のすべての文と同時にメイン・クエリでサブステートメント。そのため、実際の配列に基づいて更新することを指定しWITHデータ修正文は、予測不可能な方法で発生したとき。データを返すことはサブステートメントおよびメイン・クエリWITH異なる間の変化を伝えるための唯一の方法です。

WITH t AS (
    UPDATE products SET price = price * 1.05
    RETURNING *
)
SELECT * FROM products;

外側のSELECTは、UPDATE操作の前に元の価格に戻って、そして中にすることができます

WITH t AS (
    UPDATE products SET price = price * 1.05
    RETURNING *
)
SELECT * FROM t;

外部SELECTは、更新されたデータを返します。

使用上の注意WITH

データ変更ステートメントWITH 1は、かどうかに関係なく読むのか、メイン文はその出力のすべてを読んでいるかどうか、一度に実行され、確かに完全に実行されます。SELECTステートメントとレコードの数を必要な主な書類の出力のみWITH。

図2に示すように、サブ修正文の複数の存在は、それらの結果を予測できない同じレコードを変更並列に実行される句、及びメイン文で複数を使用する場合。

3、彼らはターゲット・データ・セットの他の文の影響を確認して、データセットが同じである「見る」ことができるすべての句。また引き起こさマルチ句の実行順序の予測不可能性の影響を緩和しました。

4、SQL文が同じレコードに反映されますのみそのうちの一つに数回、更新する場合、1つが有効になるかを予測することは困難です。

5、SQLステートメント、および更新する場合や有効にするには、レコード、更新のみを削除します。

図6は、現時点では、CTEのいずれかは、条件付きルール、およびルールの使用を許可しない、データテーブルを変更し、そして代わりルール。

RECURSIVE

オプションのRECURSIVE修飾子は、純粋な利便性になるから構文の特性を持つ標準SQLを完了することができないだろう。RECURSIVEを使用することにより、クエリを持つ独自の出力を参照することができます。

たとえば、次の表:

create table document_directories
(
    id         bigserial                                          not null
        constraint document_directories_pk
            primary key,
    name       text                                               not null,
    created_at timestamp with time zone default CURRENT_TIMESTAMP not null,
    updated_at timestamp with time zone default CURRENT_TIMESTAMP not null,
    parent_id  bigint                   default 0                 not null
);

comment on table document_directories is '文档目录';

comment on column document_directories.name is '名称';

comment on column document_directories.parent_id is '父级id';

INSERT INTO public.document_directories (id, name, created_at, updated_at, parent_id) VALUES (1, '中国', '2020-03-28 15:55:27.137439', '2020-03-28 15:55:27.137439', 0);
INSERT INTO public.document_directories (id, name, created_at, updated_at, parent_id) VALUES (2, '上海', '2020-03-28 15:55:40.894773', '2020-03-28 15:55:40.894773', 1);
INSERT INTO public.document_directories (id, name, created_at, updated_at, parent_id) VALUES (3, '北京', '2020-03-28 15:55:53.631493', '2020-03-28 15:55:53.631493', 1);
INSERT INTO public.document_directories (id, name, created_at, updated_at, parent_id) VALUES (4, '南京', '2020-03-28 15:56:05.496985', '2020-03-28 15:56:05.496985', 1);
INSERT INTO public.document_directories (id, name, created_at, updated_at, parent_id) VALUES (5, '浦东新区', '2020-03-28 15:56:24.824672', '2020-03-28 15:56:24.824672', 2);
INSERT INTO public.document_directories (id, name, created_at, updated_at, parent_id) VALUES (6, '徐汇区', '2020-03-28 15:56:39.664924', '2020-03-28 15:56:39.664924', 2);
INSERT INTO public.document_directories (id, name, created_at, updated_at, parent_id) VALUES (7, '漕宝路', '2020-03-28 15:57:14.320631', '2020-03-28 15:57:14.320631', 6);

これは、私たちがRECURSIVEの下での使用を分析するために、いくつかのデータを作成し、無制限クラスのカテゴリリストです。

WITH RECURSIVE res AS (
    SELECT id, name, parent_id
    FROM document_directories
    WHERE id = 5
    UNION
    SELECT dd.id,
           dd.name || ' > ' || d.name,
           dd.parent_id
    FROM res d
             INNER JOIN document_directories dd ON dd.id = d.parent_id
)
select *
from res

当然这个sql也可以这样写
WITH RECURSIVE res(id, name, parent_id) AS (
    SELECT id, name, parent_id
    FROM document_directories
    WHERE id = 5
    UNION
    SELECT dd.id,
           dd.name || ' > ' || d.name,
           dd.parent_id
    FROM res d
             INNER JOIN document_directories dd ON dd.id = d.parent_id
)
select *
from res

再帰クエリ処理

これは、オペレーションのドキュメントpgsqlの説明です:

1、非再帰的な用語を計算します。UNION(しかしUNION ALL)の場合は、重複する行を破棄。残りの行は、再帰クエリの結果に含まれており、一時的な作業テーブルにそれらを置くことができます。

2、限り、作業テーブルが空でないとして、次の手順を繰り返します。

再帰的な演算項は、自己参照再帰は、現在のワークシートの内容に置き換え。UNION(ないUNION ALL)の場合は、行の前に重複した結果行を持つものだけでなく、重複する行を破棄。すべての行の残りの部分は、再帰クエリの結果に含まれており、また、一時的な中間テーブルに入れて。

B中間テーブルの内容とワークシートの内容を置き換え、そして中間テーブルを空にする。

実行中のプロセスを解体

実際には、実行するために、2つの部分に分かれています。

実施形態の前部に1、非再帰的用語(非再帰部分)、すなわち組合

2、再帰的な用語(再帰部分)、後で同じ組合、すなわち

私たちは、上記のSQLの下で解体します

1、非再帰的な部分を実行します
  SELECT id, name, parent_id
    FROM document_directories
    WHERE id = 5
结果集和working table为
5	浦东新区	2
2、再帰部分、UNION場合、および一時テーブルに入れ、その後、重いことに努め、テーブルの上に現在のクエリ結果の結果を使用します。その後、一時テーブルのデータにデータ内の作動表を置き換えます。
 SELECT dd.id,
           dd.name || ' > ' || d.name,
           dd.parent_id
    FROM res d
             INNER JOIN document_directories dd ON dd.id = d.parent_id
结果集和working table为
2	上海 > 浦东新区	1
図3は、2と、データテーブルにデータが存在しなくなるまで。
 SELECT dd.id,
           dd.name || ' > ' || d.name,
           dd.parent_id
    FROM res d
             INNER JOIN document_directories dd ON dd.id = d.parent_id
结果集和working table为
1	中国 > 上海 > 浦东新区	0
4、再帰の終了ステップの前のセットの結果、そのWITH RECURSIVEの最終的な結果セット

厳密に言えば、このプロセスは反復プロセスは再帰ではなく、達成することですが、PostgreSQLはまた、recursiveキーワードを使用し続けてRECURSIVEキーワードSQL標準化委員会は、直立設定されています。

WITH RECURSIVEの使用制限

あなたはLEFTは、再帰的用語でJOINを使用した場合1は、自己参照は「左」側になっている必要があり
ますが、RIGHT再帰的な用語では、JOINを使用する場合、2、自己参照は「右」側になければならない
3、再帰的な用語はFULL JOINので許可されていない
4、再帰的な用語は、GROUP BYで許可されていないし、あっている
5、CTEは再帰的な用語の名前で声明サブクエリで許可されていない
6は、集約キーワードのCTEに再帰的用語をサポートしていません
7、再帰的な用語ORDER BY許可されていません
8は、LIMIT / OFFSETは、の再帰的用語で許可されていない
UPDATEが再帰的用語で使用することができないために、9
10、再帰的な用語は、サブクエリ参照CTEの名前で許可されていないバックSELECT
11、複数のCTE発現の同時使用をしません複数の式の間で互いに(サポート一方通行のアクセス)へのアクセスを許可
UPDATE FOR 12は、再帰的な用語では許可されていません

CTEの長所と短所

図1は、RECURSIVE WITH再帰的に使用することができるので、クエリを達成するのは容易ではない達成、または他の方法ですることができない
他のクエリ独立の共有、それは量の点よりも柔軟で軽量である場合、クエリ結果が必要とされない場合、2
3、CTEのみとなり一度計算され、メイン・クエリで繰り返し使用することができる
。4、CTEが大きく読みやすさと保守性を向上させることができる
。5、CTEは、一次制約をサポートされていない場合にCTEのクエリ押し下げ、通常のサブクエリのサポート

UNIONとUNION ALLの違い

組合の直接接続を使用して、すべてのUNIONをもっと、可能な複製組合を記録したすべての値にアクセス可能であることはユニークな値、無重複レコードを取ることです

次のように1、UNIONの構文は次のとおりです。

    [SQL 语句 1]
      UNION
     [SQL 语句 2]

2次のように、UNION ALLの構文は次のとおりです。

  [SQL 语句 1]
      UNION ALL
     [SQL 语句 2]

UNIONとUNIONすべてのキーワードを1つに両者を組み合わせた結果であり、それから利用及び効率の両方が異なっています。

1、重複した結果の取り扱い:UNIONはリンク後にテーブルを作成するには重複したレコードを除外します、連合のすべての重複レコードを削除しません。
2、ソートのプロセス:連合はフィールドの順にソートされます。UNION ALLは、単純に復帰した後、二つの結果をマージします。

あなたは2つの結果セットの合併を確認することができれば速くたくさんより効率、UNION ALL UNIONからは、そう、その後、UNION ALLを使用して、重複したデータが含まれていないケースのようなものを必要としません。

概要

  • UNIONの行くと並べ替え

  • いない再ソートUNION ALL(高効率)

概要

再帰再帰pgsqlの機構は、そのような私たちのクエリの完全なツリー構造は、この非常に完璧を使用するときのように、提供されていますが、我々はそれが、リングのデータで、無限再帰ループが発生することは避けてください。主要な文である複数の句を使用する場合、ことに留意すべきであると並列に実行される場所もちろん、彼はちょうどCTEがCTEを使用して、クエリの性質であるた、私たちは無視することはできません。私たちは、それは、単一のSQL文で実行される判断に有効になりますその一方のみが同じレコード数回、更新し、1つが有効になるかを予測することは困難であることはできません。もちろん、機能は声明で、非常に強力で、メインの文は、文のいずれかを、DELETE、SELECT、INSERT、UPDATEすることができ、我々は我々が必要とするあらゆるシーン操作を組み立てることができます。

参照

[SQLの最適化(5)はPostgreSQL(再帰的)CTE共通テーブル式] http://www.jasongj.com/sql/cte/
[WITH問い合わせ(共通テーブル式)] http://postgres.cn/docs/ 11 /クエリ-with.html
[UNIONとUNION ALL差] https://juejin.im/post/5c131ee4e51d45404123d572
[PostgreSQLの再帰クエリ(再帰付き)] https://my.oschina.net/Kenyon/blog/ 55137

おすすめ

転載: www.cnblogs.com/ricklz/p/12590618.html