7.3.1 副問合せの指定形式および規則
内側の問合せ指定を副問合せといいます。副問合せには,次の2種類があります。
-
スカラ副問合せ
問合せの結果の列数が1列で,行数が1行以下の副問合せのことです。
-
表副問合せ
問合せの結果の列数が1列以上で,行数が0行以上の副問合せのことです。
- 〈この項の構成〉
(1) 指定形式
副問合せ::=(〔副問合せ処理方式指定〕 問合せ式本体 〔ORDER BY句〕 〔LIMIT句〕)
副問合せ処理方式指定::=/*>> SUBQUERY NOT BY HASH〔副問合せ処理委譲指定〕<<*/
副問合せ処理委譲指定::=(DELEGATION)
(2) 指定形式の説明
- 副問合せ処理方式指定:
-
副問合せ処理方式指定を指定した場合,副問合せの処理方式にハッシュ実行以外の方式が適用されます。副問合せの処理方式については,マニュアルHADB AP開発ガイドの副問合せの処理方式を参照してください。
なお,通常は,この指定をする必要はありません。副問合せ処理方式指定を省略した場合,HADBが副問合せの処理方式を決定します。
また,副問合せ処理方式指定は次の個所に指定できません。
-
導出表の表副問合せ
-
問合せによるマルチ集合値構成子の表副問合せ
-
- 副問合せ処理委譲指定:
-
副問合せ処理委譲指定を指定した場合,ほかの処理で使用するSQL処理リアルスレッドを,外への参照列を含む副問合せの検索処理に振り分けることができます。
なお,通常は,この指定をする必要はありません。外への参照列を含む副問合せの結果を得るために多くの検索処理が必要な場合に,副問合せ処理委譲指定を指定することを検討してください。
(例)
SELECT COUNT(*) FROM "T1" WHERE "T1"."C1" = ANY( SELECT "T2"."C1" FROM "T2" WHERE "T1"."C2" = "T2"."C2")
上記のSQL文の場合,表T1の結果1件ごとに表T2の検索が行われます。探索条件「"T1"."C2" = "T2"."C2"」を満たす表T2の行数が多い場合,副問合せ処理委譲指定を指定すると,検索性能が向上することがあります。ただし,副問合せ処理委譲指定を指定した場合,外への参照列を含む副問合せの検索処理をほかのSQL処理リアルスレッドに振り分ける分のオーバヘッドが掛かります。そのため,検索条件によっては,検索性能が低下するおそれもあります。
副問合せ処理委譲指定に関する規則を次に示します。
-
次のどちらかの条件を満たす副問合せに副問合せ処理委譲指定を指定した場合,その副問合せ処理委譲指定は無視されます。
-
外への参照列を含まない副問合せの場合
-
副問合せを指定したSQL文に非順序実行方式が適用されない場合
(例)副問合せ処理委譲指定が無視される例
上記の例では,外への参照列を含まない副問合せに,副問合せ処理委譲指定を指定していますが,外への参照列を含む副問合せには,副問合せ処理委譲指定を指定していません。この場合,外への参照列を含む副問合せに,副問合せ処理委譲指定が指定されていないため,副問合せ処理委譲指定が無視されます。
-
-
外への参照列を含む副問合せを入れ子で指定した場合,どれか1つでも副問合せ処理委譲指定を指定していると,入れ子中のすべての外への参照列を含む副問合せに,副問合せ処理委譲指定が指定されたと見なされます。外への参照列を含む副問合せを入れ子で指定している例を次に示します。この例では,外への参照列を含む副問合せが2つ指定されていて,片方の副問合せにだけ副問合せ処理委譲指定が指定されています。この場合,2つの副問合せに対して,副問合せ処理委譲指定が指定されたと見なされます。
-
外への参照列を含む副問合せに副問合せ処理委譲指定を指定した場合,同じ表を外への参照列として参照する副問合せにも,副問合せ処理委譲指定が指定されたと見なされます。例を次に示します。この例では,同じ表を外への参照列として参照する副問合せが2つ指定されていて,片方の副問合せにだけ副問合せ処理委譲指定が指定されています。この場合,2つの副問合せに対して,副問合せ処理委譲指定が指定されたと見なされます。
-
- 問合せ式本体:
-
問合せ式本体の詳細については,「7.1.1 問合せ式の指定形式および規則」の「(2) 指定形式の説明」を参照してください。
- ORDER BY句:
-
導出表の表副問合せの場合にだけ指定できます。
問合せ式本体の検索結果を昇順または降順に並べ替える場合に指定します。ORDER BY句を省略した場合,問合せ式本体の検索結果の並び順は保証されません。
ORDER BY句については,「4.4.1 SELECT文の指定形式および規則」を参照してください。
なお,副問合せにORDER BY句を指定する場合,LIMIT句も一緒に指定する必要があります。
- LIMIT句:
-
問合せ式本体の検索結果として取得する行数の最大値を指定します。
LIMIT句については,「7.9 LIMIT句」を参照してください。
なお,LIMIT句を指定できるのは,導出表の表副問合せか,またはスカラ副問合せの場合だけです。ただし,次の場合は,導出表であっても,LIMIT句を指定できません。
-
LIMIT句を指定した導出表を超えて,外への参照を行っている導出表
(例)エラーになるSQL文の例
この場合,"T1"."C1"が,LIMIT句を指定した導出表(相関名:DRV)を超えて外への参照を行っています。そのため,LIMIT句を指定することはできません。
導出表については,「7.11.1 表参照の指定形式」を参照してください。
-
(3) 実行時に必要な権限
副問合せを実行する場合,副問合せ中で参照する表に対するSELECT権限が必要になります。
(4) 規則
(a) 副問合せ共通の規則
-
副問合せの結果のデータ型は,問合せ式本体の結果のデータ型と同じになります。
-
副問合せの結果,導出される表の列名については,「6.9 導出列名」を参照してください。
-
副問合せ中の選択式に次の指定はできません。
-
外への参照列
-
〔表指定.〕ROW
- ■外への参照列
-
外側の問合せのFROM句に指定した表を,副問合せ中の探索条件で参照している場合,これを外への参照といいます。また,参照している列を外への参照列といいます。外への参照列の例を次の図に示します。
図7‒2 外への参照列の例
-
-
副問合せを32回(ビュー定義およびWITH句の場合は31回)まで入れ子で指定できます。さらに次の規則があります。
-
FROM句に指定した表がビュー表または問合せ名の場合
ビュー表または問合せ名に内部導出表を適用したあとの副問合せの入れ子の数が32回(ビュー定義およびWITH句の場合は31回)以内となるようにしてください。
-
FROM句に指定した表が,FROM句に指定した表を含む再帰的問合せを参照する再帰的問合せ名の場合
再帰的問合せ名に対応する内部導出表を1度適用したあとの副問合せの入れ子の数が32回(ビュー定義およびWITH句の場合は31回)以内となるようにしてください。
-
FROM句にアーカイブマルチチャンク表を指定した場合
アーカイブマルチチャンク表は内部導出表に等価変換されます。内部導出表に等価変換されたあとの副問合せの入れ子の数が33個以上となった場合,そのSQL文はエラーになります。アーカイブマルチチャンク表に関する等価変換については,マニュアルHADB AP開発ガイドのアーカイブマルチチャンク表を検索するSQL文の等価変換を参照してください。
-
FROM句に表値構成子によって導出される導出表を指定した場合
副問合せの入れ子の数が1つ加算されます。
副問合せの入れ子の数の数え方の例を次に説明します。
- (例1)
-
次のSELECT文は,副問合せを8回入れ子にして指定しています。
SELECT * FROM "TT" WHERE EXISTS( SELECT * FROM "T0" WHERE EXISTS( SELECT * FROM "T1" WHERE EXISTS( ←1つ目の入れ子 SELECT * FROM "T2" WHERE EXISTS( ←2つ目の入れ子 SELECT * FROM "T3" WHERE EXISTS( ←3つ目の入れ子 SELECT * FROM "T4" WHERE EXISTS( ←4つ目の入れ子 SELECT * FROM "T5" WHERE EXISTS( ←5つ目の入れ子 SELECT * FROM "T6" WHERE EXISTS( ←6つ目の入れ子 SELECT * FROM "T7" WHERE EXISTS( ←7つ目の入れ子 SELECT * FROM "T8" ←8つ目の入れ子 )))))))))
- (例2)
-
次のCREATE VIEW文は,副問合せを7回入れ子にして指定しています。
CREATE VIEW "V1" AS SELECT * FROM "TT" WHERE EXISTS( SELECT * FROM "T0" WHERE EXISTS( SELECT * FROM "T1" WHERE EXISTS( ←1つ目の入れ子 SELECT * FROM "T2" WHERE EXISTS( ←2つ目の入れ子 SELECT * FROM "T3" WHERE EXISTS( ←3つ目の入れ子 SELECT * FROM "T4" WHERE EXISTS( ←4つ目の入れ子 SELECT * FROM "T5" WHERE EXISTS( ←5つ目の入れ子 SELECT * FROM "T6" WHERE EXISTS( ←6つ目の入れ子 SELECT * FROM "T7" ←7つ目の入れ子 ))))))))
次のSELECT文を実行した場合,内部導出表が適用されて,副問合せの入れ子の数は8回になります。
SELECT * FROM "V1"
- (例3)
-
次のSELECT文を実行した場合,内部導出表が適用されて,副問合せの入れ子の数は8回になります。
WITH "Q1" AS (SELECT * FROM "TT" WHERE EXISTS( SELECT * FROM "T0" WHERE EXISTS( SELECT * FROM "T1" WHERE EXISTS( ←1つ目の入れ子 SELECT * FROM "T2" WHERE EXISTS( ←2つ目の入れ子 SELECT * FROM "T3" WHERE EXISTS( ←3つ目の入れ子 SELECT * FROM "T4" WHERE EXISTS( ←4つ目の入れ子 SELECT * FROM "T5" WHERE EXISTS( ←5つ目の入れ子 SELECT * FROM "T6" WHERE EXISTS( ←6つ目の入れ子 SELECT * FROM "T7" ←7つ目の入れ子 ))))))))) SELECT * FROM "Q1" ←内部導出表が適用された結果,8つ目の入れ子となる
- (例4)
-
次のSELECT文のFROM句には,再帰的問合せ名Q1が指定されています。次のSELECT文を実行した場合,内部導出表が適用されて,副問合せの入れ子の数は8回になります。
実行するSQL文:
WITH "Q1" AS (SELECT "C1" FROM "TT" UNION ALL SELECT "C1"+1 FROM "Q1" WHERE "C1"+1 < 5) SELECT * FROM "TT" WHERE EXISTS( SELECT * FROM "T0" WHERE EXISTS( SELECT * FROM "T1" WHERE EXISTS( SELECT * FROM "T2" WHERE EXISTS( SELECT * FROM "T3" WHERE EXISTS( SELECT * FROM "T4" WHERE EXISTS( SELECT * FROM "T5" WHERE EXISTS( SELECT * FROM "Q1")))))))
内部導出表が適用されたあとのSQL文:
SELECT * FROM "TT" WHERE EXISTS( SELECT * FROM "T0" WHERE EXISTS( SELECT * FROM "T1" WHERE EXISTS( ←1つ目の入れ子 SELECT * FROM "T2" WHERE EXISTS( ←2つ目の入れ子 SELECT * FROM "T3" WHERE EXISTS( ←3つ目の入れ子 SELECT * FROM "T4" WHERE EXISTS( ←4つ目の入れ子 SELECT * FROM "T5" WHERE EXISTS( ←5つ目の入れ子 SELECT * FROM ←6つ目の入れ子 (SELECT "C1" FROM "TT" ←7つ目の入れ子 UNION ALL SELECT "C1"+1 FROM (SELECT "C1" FROM "TT" ←8つ目の入れ子 UNION ALL SELECT "C1"+1 FROM "Q1" WHERE "C1"+1 < 5)"Q1" WHERE "C1"+1 < 5)"Q1")))))))
- (例5)
-
次のSELECT文は,副問合せを7回入れ子にして指定しています。また,FROM句に表値構成子によって導出される導出表を指定しているため,副問合せの入れ子の数が1つ加算されます。したがって,合計8回の入れ子が指定されていると見なされます。
SELECT * FROM "TT" WHERE EXISTS( SELECT * FROM "T0" WHERE EXISTS( SELECT * FROM "T1" WHERE EXISTS( ←1つ目の入れ子 SELECT * FROM "T2" WHERE EXISTS( ←2つ目の入れ子 SELECT * FROM "T3" WHERE EXISTS( ←3つ目の入れ子 SELECT * FROM "T4" WHERE EXISTS( ←4つ目の入れ子 SELECT * FROM "T5" WHERE EXISTS( ←5つ目の入れ子 SELECT * FROM "T6" WHERE EXISTS( ←6つ目の入れ子 SELECT * FROM (VALUES (1,2,3)) "T7" ←7~8つ目の入れ子 ))))))))
-
-
集合関数中に副問合せは指定できません。
-
ウィンドウ関数中に副問合せは指定できません。
-
GROUP BY句のグループ化指定に副問合せは指定できません。
-
FULL OUTER JOINを指定した結合表のON 探索条件に,副問合せは指定できません。
-
行値構成子要素中に副問合せは指定できません。
-
FULL OUTER JOINを指定した結合表中の表参照を参照先とする,外への参照を行う列は指定できません。
(例)下線の部分が誤っている外への参照列です。
SELECT * FROM ("T1" LEFT OUTER JOIN "T2" ON "T1"."C1"="T2"."C1") FULL OUTER JOIN "T3" ON "T1"."C2"="T3"."C2" WHERE "T1"."C3">(SELECT MAX(C3) FROM "T4" WHERE "C1"="T1"."C1" AND "C2"="T3"."C2")
(b) スカラ副問合せの規則
-
スカラ副問合せの結果の列数は1にしてください。
-
スカラ副問合せの結果の行数は1以下にしてください。結果の行数が2以上の場合,SQLエラーとなります。
-
スカラ副問合せの結果の行数が0の場合,その結果はナル値となります。
-
スカラ副問合せの結果は,非ナル値制約なし(ナル値を許す)となります。
-
スカラ副問合せの選択式の値式には,配列データを指定できません。
(c) 表副問合せの規則
-
表副問合せの結果の列数の最大値を次に示します。
-
導出表に指定した表副問合せの場合:4,000
-
IN述語,および限定述語の右側に指定した表副問合せの場合:1
-
EXISTS述語に指定した表副問合せの場合:4,000
-
(5) 例題
- 例題1
-
最も給与が高い社員の名前(NAME),給与(SAL)を検索します。
SELECT "NAME","SAL" FROM "SALARYLIST" WHERE "SAL"=(SELECT MAX("SAL") FROM "SALARYLIST")
下線部分が副問合せの指定です。
- 例題2
-
全社員の平均給与より,平均給与が高い部門(SCODE)の平均給与額を検索します。
SELECT "SCODE",AVG("SAL") FROM "SALARYLIST" GROUP BY "SCODE" HAVING AVG("SAL")>(SELECT AVG("SAL") FROM "SALARYLIST")
下線部分が副問合せの指定です。
- 例題3
-
販売履歴表(SALESLIST)から任意の100行を取得し,その取得結果に対して商品コード(PUR-CODE)ごとに,販売個数(PUR-NUM)の合計値を求めます。
SELECT "PUR-CODE",SUM("PUR-NUM") FROM (SELECT * FROM "SALESLIST" LIMIT 100) "SALESLIST" GROUP BY "PUR-CODE"
下線部分が副問合せの指定です。
(6) 留意事項
-
副問合せを指定した場合,作業表が作成されることがあります。作業表が作成される作業表用DBエリアの容量が正しく見積もられていない場合,性能低下の原因となることがあります。作業表用DBエリアの容量見積もりについては,マニュアルHADB システム構築・運用ガイドを参照してください。作業表の詳細については,マニュアルHADB AP開発ガイドの作業表が作成されるSQLを実行する際の考慮点を参照してください。
-
副問合せの処理方式にハッシュ実行が適用された場合,適切な大きさのハッシュテーブル領域が必要になります。ハッシュテーブル領域の大きさはサーバ定義またはクライアント定義のadb_sql_exe_hashtbl_area_sizeオペランドで指定します。また,副問合せの処理方式にハッシュ実行が適用された場合,ハッシュフィルタを格納するハッシュフィルタ領域も必要になります。ハッシュフィルタ領域の大きさは,サーバ定義またはクライアント定義のadb_sql_exe_hashflt_area_sizeオペランドで指定します。副問合せの処理方式については,マニュアルHADB AP開発ガイドの副問合せの処理方式を参照してください。