サブクエリ(その1)

サブクエリとは

 クエリ内で関数を使用するのと同じように、SQL(Select文)を記入することでそのSQLの実行結果を利用することができます。そのクエリ内にあるSQLをサブクエリといいます(日本語では「副照会」といいます)。
 箇所によっては複数の値を返すSQLを利用することもでき、また、複数のテーブルの結合結果を返すSQLを利用することもできますので、関数だけでは実現できないような複雑なクエリも作成することができます。多数のクエリを組み合わせて必要なクエリを作成している場合、クエリの数の削減を図ることもできます。
 当然ながらSQLの知識を必要としますので、まずそちらから先に学習する必要があります。

サブクエリの例

サブクエリの例1(値を表示させる)
 例として次のようなテーブル「T_成績」を用います。




 サブクエリを使って、この「点数」の平均つまり平均点を表示させてみましょう。
 デザインビューでこのテーブルを使ったクエリを作成し、新たな列として「平均点: (select avg([点数]) from T_成績)」と記入します。「平均点:」の部分は列の名称を定めている部分です。それに続くSQL(SELECT文)がサブクエリですが、カッコでくくるのを忘れないようにしてください。




 これをデータシートビューで表示すると、各レコードに平均点が表示されていることがわかります。




 平均点を求めるには、他に定義域集計関数(この場合はDAvg関数)を使ったり、平均点を求めるクエリを別に作っておく方法も考えられますが、クエリ内にSQLを書き込むことで同じ結果が得られることがわかりました。これがサブクエリの実例です。

 次にちょっとした応用として、偏差値を求めてみます。
 全体の平均点と標準偏差、そして当該個人の点数をもとに偏差値を算出することができます。簡易に表現すると
 偏差値=50+10*(点数-平均点)/標準偏差
となりますが、これを上記のテーブルの内容に即したサブクエリとして表すと
 「偏差値: 50+10*([点数]-(select avg([点数]) from T_成績))/(select stdev([点数]) from T_成績)」
となります。「(select avg([点数]) from T_成績)」が先ほどと同じく平均点を求めるSQL、「(select stdev([点数]) from T_成績)」が標準偏差を求めるSQLです。
 これをデザインビューで記入します。カッコ(SQLをくくるものと計算順を示すためのもの)が増えますが、間違えないように注意してください。



 これをデータシートビューで開くと、各レコードに偏差値が表示されていることがわかります。
 なお、適当な桁で丸める場合はさらにInt関数などを使うこととなります。



サブクエリの例2(抽出条件(Where句)に利用する)
 サブクエリはクエリ内で用いられる様々な値を置き換えることができます。例えば抽出条件の指定にも利用することが出来ます。
 例として上記のテーブル「T_成績」を利用したクエリを作成し、平均点以上のレコードを抽出してみます。「点数」列の「抽出条件」の欄に「>=(select avg([点数]) from T_成績)」と記入します。



 データシートビューで開くと、平均点(72.25)以上のレコードのみが表示されていることがわかります。



 サブクエリは当然ながらAnd、OrやBetween句にも利用できます。
 次のクエリは平均点プラスマイナス10点の区間に含まれるレコードを抽出します。



 データシートビューは次のとおりとなります。



サブクエリの例3(Where〜In句に利用する)
 In句には複数の値を並べることで、それらのいずれかに該当する、という抽出条件を設定することができます。




 これらの値を直接指定する代わりに、複数の値を返すサブクエリを置くことができます。通常サブクエリで複数の値が返されるとエラーになってしまいますが、In句では問題ありません。
 例として次のような2つのテーブルを考えてみます。最初のテーブル「T_成績」は上記の例と同じで、2つ目のテーブル「T_欠席」は各人の欠席の状況を記すテーブルとなっています。




 「T_成績」をもとにクエリを作成し、IDの抽出条件内にIn句、そしてサブクエリ「(select ID from T_欠席 group by ID having count(*)>=2)」を記入します。このサブクエリは2回(2日)以上の欠席がある者のIDを抽出しています。よってこのクエリ全体としては、2回(2日)以上の欠席がある者の成績を表すものとなります。
 なおIn句もサブクエリもそれぞれカッコを必要としますが、ここではサブクエリを2重のカッコで囲う必要はありません。1つで大丈夫です。




 データシートビューは次のようになります。




 テーブルが2つの例を挙げましたが、テーブルが1つのシンプルなデータベースの場合はIn句でのサブクエリを使う機会はほぼありません(サブクエリで条件を設定してIn句を生成しそれに該当するレコードを抽出するよりも、Where句で直接条件を設定してレコードを抽出した方が早いからです)。また、複数のテーブルからクエリを作成する場合でも、たいていの条件はJoin句など他の方法で設定できるので使いどころを考える必要があります。