前提
下記のような通常のselect文(超基礎)が理解できる状態である。
この次に何を覚えればよいかを片っ端から書いていく。
select * from students where id = 2;
order句
表示順を指定する。limit や offset はあまり使われない印象。
select * from students order by id; --ID順(昇順)に並べ替え
select * from students order by id desc; --ID順(降順)に並び替え
select * from students order by name desc, height; --名前順(降順)→身長順(昇順)に並び替え
select * from students order by id limit 2; --並び替え後、先頭の2件を表示
select * from students order by id offset 3; --並び替え後、先頭の3件をスキップして残りを表示
select * from students order by id limit 2 offset 1; --並び替え後、先頭の1行をスキップして、先頭の2件を表示
group句
select句の対象に集約関数(sum, avg, max, min, countなど)を使用できる。
例えば数学のテストの平均値を男女で比較したい、といった場合は「性別」をグループ化して、国語の点数カラムの値を見る。
select avg(math) from students group by gender;
--性別でグループ化して、平均値をみる集約関数を使用
select max(math), min(math), sum(math), count(*), to_char(avg(math), '99.9')
from students group by gender;
--最大値、最小値、合計値、レコード数、平均値を[xx.x]形式に変換した文字列、を性別ごとに集計
group句の注意点:select対象
group句の場合、select句の対象に選択できるカラムに制限がかかる。
例えばstudentsテーブルに対して「gender」でグループ化しているとき、「id」や「name」カラムなど、group句の対象でも集約関数でもないものは出力できない。
実行結果は「gender」に集約されているので、ここでいうと「男性」「女性」の2行しか出力されない状態である。
そこで「name」を表示しようとしても一体誰の名前を表示すればいいのか?と考えれば納得できる。
select avg(math), name from students group by gender; --構文エラーになる
group句の対象は「式」である
列名での集約はイメージしやすいが、関数を用いた式もgroup句の対象に指定できる。
そもそも列名は「式」に分類されるものなので、group句の対象には「式」を指定できる、と理解するとよい。
select * from students group by length(name);
having句
グループ化したデータに対して絞り込みをする場合、having句を使用する。
動作のイメージは where句に近い。
select avg(math) from students group by gender having avg(math) >= 60;
--性別ごとの数学の平均点を求めて、平均点が60以上ではない場合はその性別のデータを表示しない。
--例:男子の平均点が50、女子の平均点が70の場合、男子のデータは表示されない。切ないね。
SQLの実行順序という意識
この節は不確定情報が多いので不備があれば指摘いただけると助かります!
例えば「数学のテストが平均点以上の生徒の名前を知りたい」という場合、こんなSQLをイメージするが、実行できない。
select name from students where math >= avg(math);
SQL文の実行順序のイメージは、select句を除いて上から順番に from句→where句→group句…と実行していき、select句を最後に実行する、というもの。
avgは平均値を求める集約関数であり、テーブルのデータを集約してから算出される。
つまりgroup句以降(select句を含む)でなければavg関数を使用できないので、where句で集約関数を参照することはできない(本稿では触れないが、サブクエリを使用すれば解決する)。
また select句が実行されるときはテーブルのデータが集約された後なので、そもそもname列がデータに存在していない状態になる。