サブクエリとは、SELECT文の中に別のSELECT文を1つ以上ネストしたもので、単一行、複数行の結果を返す場合もあれば、結果を返さない場合もあります。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