この記事は技術的すぎるため、ほとんどの読者には理解しにくいかもしれません。技術的な詳細を削除せずに、(2018年4月) |
階層クエリは、階層モデルデータを処理するSQLクエリの一種です。これは、推移閉包を計算する、より一般的な再帰的固定点クエリの特殊なケースです。
標準SQL:1999では、階層クエリは再帰共通テーブル式(CTE)によって実装されています。Oracle の以前のconnect-by 句とは異なり、再帰 CTE は最初から固定小数点セマンティクスで設計されました。[ 1 ]標準の再帰 CTE は、IBM DB2 バージョン 2 の既存の実装に比較的近いものでした。[ 1 ]再帰 CTE は、Microsoft SQL Server (SQL Server 2008 R2 以降)、[ 2 ] Firebird 2.1、[ 3 ] PostgreSQL 8.4+、[ 4 ] SQLite 3.8.3+、[ 5 ] IBM Informixバージョン 11.50+、CUBRID、MariaDB 10.2 +、 MySQL 8.0.1+でもサポートされています。[ 6 ] Tableau には、CTE の使用方法を説明したドキュメントがあります。 TIBCO Spotfire は CTE をサポートしていませんが、Oracle 11g Release 2 の実装には固定小数点セマンティクスがありません。
共通テーブル式やconnected-by句を使わずに、ユーザー定義の再帰関数を使用して階層的なクエリを実現することが可能です。[ 7 ]
このセクションは拡張が必要です。不足している情報を追加してご協力ください。 (2012年11月) |
共通テーブル式 (CTE) ( SQLの場合) は、単純なクエリから派生しSELECT、、、、またはステートメントの実行スコープ内で定義される一時的な名前付き結果セットです。 INSERTUPDATEDELETE
CTE は、派生テーブル (サブクエリ)、ビュー、およびインライン ユーザー定義関数 の代替として考えることができます。
共通テーブル式は、 Teradata(バージョン14以降)、IBM Db2、Informix(バージョン14.1以降)、Firebird(バージョン2.1以降)[ 8 ] Microsoft SQL Server(バージョン2005以降)、Oracle(11gリリース2以降の再帰機能付き)、PostgreSQL(8.4以降)、MariaDB(10.2以降[ 9 ])、MySQL(8.0以降)、SQLite(3.8.3以降)、HyperSQL、Informix(14.10以降)[ 10 ] Google BigQuery、Sybase(バージョン9以降)、Vertica、H2(実験的)[ 11 ]など、多数の製品でサポートされています。OracleではCTEを「サブクエリファクタリング」と呼んでいます。[ 12 ]
CTE の構文 (再帰的である場合とそうでない場合があります) は次のとおりです。
WITH [ RECURSIVE ] with_query [, ...] SELECT ...with_queryの構文は 次のとおりです。
クエリ名[ (列名[,...]) ] AS ( SELECT ...)再帰CTEはリレーション(グラフやツリーなど)をトラバースするために使用できますが、擬似列(LEVEL下記のような)が自動的に生成されないため、構文はより複雑になります。擬似列が必要な場合は、コード内で作成する必要があります。チュートリアルの例については、MSDNドキュメント[ 2 ]またはIBMドキュメント[ 13 ] [ 14 ]を参照してください。
RECURSIVEPostgreSQL以外のシステムでは、WITHの後にこのキーワードは通常必要ありません。 [ 15 ]
SQL:1999では、再帰クエリ(CTE)はクエリが許される場所であればどこにでも記述できます。例えば、CREATE[ RECURSIVE]を使って結果に名前を付けることが可能ですVIEW。[ 16 ]内でCTEを使用することでINSERT INTO、再帰クエリから生成されたデータをテーブルに取り込むことができます。この手法を用いることで、手続き型文を一切使用せずにランダムなデータ生成が可能になります。[ 17 ]
PostgreSQLのような一部のデータベースでは、より短いCREATE RECURSIVE VIEW形式をサポートしており、これは内部的にWITH RECURSIVEコーディングに変換されます。[ 18 ]
0 から 9 までの数値の 階乗を計算する再帰クエリの例を次に示します。
WITH recursive temp ( n , fact ) AS ( SELECT 0 , 1 -- 初期サブクエリUNION ALL SELECT n + 1 , ( n + 1 ) * fact FROM temp WHERE n < 9 -- 再帰サブクエリ) SELECT * FROM temp ;CONNECT BY代替構文として、1980年代にOracleによって導入された非標準構文があります。 [ 19 ] Oracle 10gより前では、この構文は循環を検出するとエラーを返すため、非循環グラフの走査にのみ有用でした。バージョン10gでは、OracleはNOCYCLE機能(およびキーワード)を導入し、循環が存在する場合でも走査が機能するようになりました。[ 20 ]
CONNECT BYは、 Snowflake、EnterpriseDB、[ 21 ] Oracleデータベース、[ 22 ] CUBRID、[ 23 ] IBM Informix [ 24 ]およびIBM Db2でサポートされていますが、互換モードとして有効になっている場合のみです。[ 25 ]構文は次のとおりです。
SELECT select_list FROM table_expression [ WHERE ... ] [ START WITH start_expression ] CONNECT BY [ NOCYCLE ] { PRIOR child_expr = parent_expr | parent_expr = PRIOR child_expr } [ ORDER SIBLINGS BY column1 [ ASC | DESC ] [, column2 [ ASC | DESC ] ] ... ] [ GROUP BY ... ] [ HAVING ... ] ...SELECT LEVEL , LPAD ( ' ' , 2 * ( LEVEL - 1 )) || ename "従業員" 、empno 、mgr "マネージャー" FROM emp START WITH mgr IS NULL CONNECT BY PRIOR empno = mgr ;上記のクエリの出力は次のようになります。
レベル | 従業員 | 従業員番号 | マネージャー -------+-------------+--------+--------- 1 | キング | 7839 | 2 | ジョーンズ | 7566 | 7839 3 | スコット | 7788 | 7566 4 | アダムス | 7876 | 7788 3 | フォード | 7902 | 7566 4 | スミス | 7369 | 7902 2 | ブレイク | 7698 | 7839 3 | アレン | 7499 | 7698 3 | 病棟 | 7521 | 7698 3 | マーティン | 7654 | 7698 3 | ターナー | 7844 | 7698 3 | ジェームズ | 7900 | 7698 2 | クラーク | 7782 | 7839 3 | ミラー | 7934 | 7782 (14行)
次の例は、部門10の各従業員の姓、階層内でその従業員の上位の各マネージャー、マネージャーと従業員間のレベル数、および両者間のパスを返します
SELECT ename "Employee" , CONNECT_BY_ROOT ename "Manager" , LEVEL - 1 "Pathlen" , SYS_CONNECT_BY_PATH ( ename , '/' ) "Path" FROM emp WHERE LEVEL > 1 AND deptno = 10 CONNECT BY PRIOR empno = mgr ORDER BY "Employee" , "Manager" , "Pathlen" , "Path" ;SYS_CONNECT_BY_PATH学術教科書。これらはSQL:1999標準(およびDatalog)のみをカバーしており、Oracle拡張機能はカバーしていないことに注意してください