階層クエリ(Hierarchical Query)は、特殊な機能を持つクエリステートメントであり、階層データを階層関係に従って表示することができます。
階層データとは、リレーショナルテーブル内のデータ間に階層関係が存在することを指します。このような関係は現実生活において非常に一般的であり、例は以下の通りです:
組織構造におけるグループリーダーとグループメンバーとの関係
企業における上司部門と部下部門との関係
Webページにおけるページ遷移の関係
使用上の制限と注意事項
階層クエリに FOR UPDATE 句が含まれる場合、以下のユースケースはサポートされません:
- サブクエリで
DISTINCTキーワードや集計が使用されている場合。この場合、FOR UPDATEと併用できません。 - すべての共通テーブル式(Common Table Expressions、CTE)を含むシナリオはサポートされていません。つまり、
WITH ... AS ...句を持つSELECTクエリはFOR UPDATEと同時に使用できません。WITH ... AS ...句の詳細については、WITH CLAUSEを参照してください。
データベースの正常な操作とパフォーマンス最適化を確保するため、上記の2つのシナリオで FOR UPDATE 句の使用は避けてください。
構文
単純階層クエリの SELECT 構文は以下のとおりです:
SELECT [LEVEL], column, expr... FROM table [WHERE condition]
[ START WITH start_expression ] CONNECT BY [NOCYCLE] { PRIOR child_expr = parent_expr | parent_expr = PRIOR child_expr } [ ORDER SIBLINGS BY ...]
[ GROUP BY ... ] [ HAVING ... ] [ ORDER BY ... ]
[FOR UPDATE [OF column] [ {NOWAIT | WAIT integer | SKIP LOCKED } ] ]
SELECT 構文の詳細については、SIMPLE SELECTを参照してください。
パラメータの説明
パラメータ |
説明 |
|---|---|
| LEVEL | レベル、すなわちノードの階層を表す疑似列です。クエリの開始点から数え、開始点は1で、それに続いて順次増えます。 |
| CONNECT_BY_ISLEAF | 現在のデータ行が階層構造内の葉ノードかどうかを示す疑似列です。
|
| CONNECT_BY_ISCYCLE | 現在のデータ行がサイクル内にあるかどうかを示す疑似列です。
|
| CONNECT_BY_ROOT | CONNECT_BY_ROOT は単項演算子で、パラメータに指定された列が階層クエリのルートノードから取得されたものであることを示します。単項の + および - と同じ優先順位を持ちます。 |
| condition | 条件を指定します。 |
| CONNECT BY | 親子関係を判断する方法を指定します。通常は等価式を使用しますが、他の式もサポートされています。 |
| START WITH | 階層クエリのルート行(Root Row)を指定します。 |
| PRIOR | PRIOR は単項演算子で、パラメータに指定された列が親行(Parent Row)から取得されたものであることを示します。単項の + および - と同じ優先順位を持ちます。 |
| NOCYCLE | このキーワードを指定すると、実行結果にサイクルが含まれていても結果を返すことができます。CONNECT_BY_ISCYCLE サイクルが発生した場所を指定するための仮想列を使用できます。指定しない場合、クライアントにエラーが返されます。 |
| ORDER SIBLINGS BY | 同一階層の行間の並べ替え順序を指定します。 |
| FOR UPDATE | オプションです。クエリ結果のすべての行に排他的ロックをかけて、他のトランザクションによる同時変更や、特定のトランザクション分離レベルでの同時読み取りを防ぎます。
|
実行プロセス
階層クエリを使用および実装する上で最も重要なのは、その実行プロセスを理解することです。一般的な階層クエリの実行プロセスは以下のとおりです:
FROM句の後に続くSCANまたはJOIN操作を実行します。START WITHおよびCONNECT BYの内容に基づいて階層関係の結果を生成します。ステップ2での階層関係の生成プロセスは、以下のように理解できます:
START WITH句の式に基づいてルート行(Root Rows)を取得します。CONNECT BY句の式に基づいて、各ルート行(Root Rows)の子行(Child Rows)を選択します。
ステップ2で生成された子行(Child Rows)を新しいルート行(Root Rows)として、さらに子行(Child Rows)を生成します。新しい行が生成されなくなるまでこの処理を繰り返します。
残りの句(例:
WHERE、GROUP BY、ORDER BYなど)を通常のクエリ実行プロセスに従って実行します。
例
テーブル
empを作成し、emp_id、position、mgr_id列にデータを挿入します。CREATE TABLE emp(emp_id INT,position VARCHAR(50),mgr_id INT); INSERT INTO emp VALUES (1,'グローバルマネージャー',NULL); INSERT INTO emp VALUES (2,'ヨーロッパ地区マネージャー',1); INSERT INTO emp VALUES (3,'アジア太平洋地区マネージャー',1); INSERT INTO emp VALUES (4,'アメリカ地区マネージャー',1); INSERT INTO emp VALUES (5,'イタリア地区マネージャー',2); INSERT INTO emp VALUES (6,'フランス地区マネージャー',2); INSERT INTO emp VALUES (7,'中国地区マネージャー',3); INSERT INTO emp VALUES (8,'韓国地区マネージャー',3); INSERT INTO emp VALUES (9,'日本地区マネージャー',3); INSERT INTO emp VALUES (10,'アメリカ地区マネージャー',4); INSERT INTO emp VALUES (11,'カナダ地区マネージャー',4); INSERT INTO emp VALUES (12,'北京地区マネージャー',7);上記の例では、テーブルの
position列には明確な階層関係があります。ツリー構造は以下のとおりです:
以下のステートメントを実行して、結果を階層構造で表示します。
SELECT emp_id, mgr_id, position, level FROM emp START WITH mgr_id IS NULL CONNECT BY PRIOR emp_id = mgr_id;実行結果は次のとおりです:
+--------+--------+--------------------+-------+ | EMP_ID | MGR_ID | POSITION | LEVEL | +--------+--------+--------------------+-------+ | 1 | NULL | グローバルマネージャー | 1 | | 2 | 1 | ヨーロッパ地区マネージャー | 2 | | 5 | 2 | イタリア地区マネージャー | 3 | | 6 | 2 | フランス地区マネージャー | 3 | | 3 | 1 | アジア太平洋地区マネージャー | 2 | | 7 | 3 | 中国地区マネージャー | 3 | | 12 | 7 | 北京地区マネージャー | 4 | | 8 | 3 | 韓国地区マネージャー | 3 | | 9 | 3 | 日本地区マネージャー | 3 | | 4 | 1 | アメリカ地区マネージャー | 2 | | 10 | 4 | アメリカ地区マネージャー | 3 | | 11 | 4 | カナダ地区マネージャー | 3 | +--------+--------+--------------------+-------+ 12 rows in set「アジア太平洋地区」の階層構造のみを照会し、
FOR UPDATE句を使用してクエリ結果をロックします。SELECT emp_id, mgr_id, position, LEVEL FROM emp START WITH position = 'アジア太平洋地区マネージャー' CONNECT BY PRIOR emp_id = mgr_id FOR UPDATE;実行結果は次のとおりです:
+--------+--------+-----------------+-------+ | EMP_ID | MGR_ID | POSITION | LEVEL | +--------+--------+-----------------+-------+ | 3 | 1 | アジア太平洋地区マネージャー | 1 | | 7 | 3 | 中国地区マネージャー | 2 | | 12 | 7 | 北京地区マネージャー | 3 | | 8 | 3 | 韓国地区マネージャー | 2 | | 9 | 3 | 日本地区マネージャー | 2 | +--------+--------+-----------------+-------+ 5 rows in set