サブクエリとは、SELECTクエリステートメント内に他の1つまたは複数のSELECTステートメントがネストされているものを指し、単一行の結果、複数行の結果、または結果を返さない場合もあります。SELECTステートメントのFROM句内のサブクエリは、インラインビューとも呼ばれます。埋め込みビュー内に任意の数のサブクエリをネストできます。SELECTステートメントのWHERE句内のサブクエリは、ネストサブクエリとも呼ばれます。
サブクエリは、関連サブクエリと非関連サブクエリに分類できます。関連サブクエリとは、そのサブクエリの実行が外部クエリの変数に依存するものであり、このようなサブクエリは通常複数回実行されます。非関連サブクエリとは、そのサブクエリの実行が外部クエリの変数に依存しないものであり、このようなサブクエリは一般的に一度だけ計算すれば済みます。非関連サブクエリおよび一部の関連サブクエリについては、書き換えることでサブクエリを排除し、ネストサブクエリの展開を実現できます。
サブクエリ構文
サブクエリの一般的な構文は以下のとおりです:
SELECT [ hint ] [ { { DISTINCT | UNIQUE } | ALL } ] select_list
FROM { table_reference | join_clause | ( join_clause ) }
[ , { table_reference | join_clause | (join_clause) } ]
[ where_clause ]
[ hierarchical_query_clause ]
[ group_by_clause ]
| subquery { UNION [ALL] | INTERSECT | MINUS } subquery [ { UNION [ALL] | INTERSECT | MINUS } subquery ]
| ( subquery ) [ order_by_clause ] [ row_limiting_clause ]
パラメータの説明は以下の表を参照してください。
| パラメータ | 説明 |
|---|---|
| select_list | クエリ対象のリストを指定します。 |
| subquery | サブクエリ。 |
| hint | コメント。 |
| table_reference | クエリ対象のターゲットテーブル。 |
サブクエリ内の列と外部クエリ内の列が同じ列名を持つ場合、外部クエリでは重複する列名の前にテーブル名を付けるか、エイリアスを使用する必要があります。
上位クエリがサブクエリ内の関連列を参照する場合、サブクエリが実行されます。上位クエリは SELECT、UPDATE、または DELETE ステートメントであり、各ステートメントでのサブクエリの使用方法は以下のとおりです:
INSERTまたはCREATE TABLEステートメントに挿入するターゲットテーブル内の行セットを定義します。CREATE VIEWまたはCREATE MATERIALIZED VIEWステートメントで、ビューに含める行セットを定義します。UPDATEで既存の行に割り当てる1つ以上の値を定義します。WHERE句、HAVING句、またはSTART WITHで条件値を提供します。クエリ操作を含むテーブルを定義します。
ネストされたサブクエリの展開(Unnesting of Nested Subqueries)
ネストされたサブクエリの展開は、データベースの最適化戦略の一つであり、一部のサブクエリを外部の親クエリ内に配置することで、実質的に特定のサブクエリを同等の複数テーブル結合操作に変換します。この戦略の明らかな利点は、アクセスパス、結合方法、結合順序を効果的に活用し、クエリの階層を可能な限り削減できることです。
データベースは、以下の場合にネストされたサブクエリの展開を行います:
関連性のない
INサブクエリ。INおよびEXISTS内の関連サブクエリに集計関数やGROUP BY句が含まれていない場合。
Hint UNNEST を使用して、ネストされたサブクエリを展開するかどうかを制御できます。
例
次のステートメントは、テーブル table_a とテーブル table_b を作成し、テーブルにデータを挿入します。
CREATE TABLE table_a(PK INT, name VARCHAR(25));
INSERT INTO table_a VALUES(1,'Fox');
INSERT INTO table_a VALUES(2,'Police');
INSERT INTO table_a VALUES(3,'Taxi');
INSERT INTO table_a VALUES(4,'Lincoln');
INSERT INTO table_a VALUES(5,'Arizona');
INSERT INTO table_a VALUES(6,'Washington');
INSERT INTO table_a VALUES(7,'Dell');
INSERT INTO table_a VALUES(10,'Lucent');
CREATE TABLE table_b(PK INT, name VARCHAR(25));
INSERT INTO table_b VALUES(1,'Fox');
INSERT INTO table_b VALUES(2,'Police');
INSERT INTO table_b VALUES(3,'Taxi');
INSERT INTO table_b VALUES(6,'Washington');
INSERT INTO table_b VALUES(7,'Dell');
INSERT INTO table_b VALUES(8,'Microsoft');
INSERT INTO table_b VALUES(9,'Apple');
INSERT INTO table_b VALUES(11,'Scotch Whisky');
依存関係のないサブクエリ
obclient> SELECT * FROM TABLE_A T1 WHERE T1.PK IN (SELECT T2.PK FROM TABLE_B T2); +------+-----------+ | PK | NAME | +------+-----------+ | 1 | Fox | | 2 | Police | | 3 | Taxi | | 6 | Washington | | 7 | Dell | +------+-----------+ 5 rows in set依存関係のあるサブクエリ。サブクエリで外部クエリ変数 T1.PK が使用されています。
SELECT * FROM TABLE_A T1 WHERE T1.PK IN (SELECT T2.PK FROM TABLE_B T2 WHERE T2.PK = T1.PK); +------+-----------+ | PK | NAME | +------+-----------+ | 1 | Fox | | 2 | Police | | 3 | Taxi | | 6 | Washington | | 7 | Dell | +------+-----------+ 5 rows in set依存関係のあるサブクエリが展開され、結合に書き換えられました。
obclient> EXPLAIN SELECT * FROM TABLE_A T1 WHERE T1.PK IN (SELECT T2.NAME FROM TABLE_B T2 WHERE T2.NAME = T1.NAME); +------------------------------------+ | Query Plan | +------------------------------------+ ============================================= |ID|OPERATOR |NAME|EST. ROWS|COST| --------------------------------------------- |0 |HASH RIGHT SEMI JOIN| |8 |107 | |1 | TABLE SCAN |T2 |8 |38 | |2 | TABLE SCAN |T1 |8 |38 | ============================================= Outputs & filters: ------------------------------------- 0 - output([T1.PK], [T1.NAME]), filter(nil), equal_conds([T1.PK = T2.NAME], [T2.NAME = T1.NAME]), other_conds(nil) 1 - output([T2.NAME]), filter(nil), access([T2.NAME]), partitions(p0) 2 - output([T1.NAME], [T1.PK]), filter(nil), access([T1.NAME], [T1.PK]), partitions(p0) +------------------------------------+ 1 row in set