「乗員は全部で何人?」「給料の平均はいくら?」——こういう質問に、これまで学んだSELECTやWHEREだけで答えられるでしょうか?
WHEREやORDER BYは「行そのもの」を扱う道具でした。でも「件数」や「合計」「平均」は、行を1つずつ見るのではなく、全体をまとめた1つの数字です。少し考えてから読み進めてください。
集計関数とは
複数の行をまとめて1つの値にする関数を、集計関数と呼びます。代表的なものは次の5つです。
COUNT()― 件数を数えるSUM()― 合計を求めるAVG()― 平均を求めるMAX()― 最大値を求めるMIN()― 最小値を求める
crewテーブルで確認しましょう。アマテラスの乗員は全部で10人ですが、そのうちトウマとリョウは、まだ配属先が決まっておらずhomeが未設定(NULL)です。
crew テーブル:
| id | name | role | age | home | salary |
|---|---|---|---|---|---|
| 1 | ユミ | エンジニア | 24 | 地球 | 320000 |
| 2 | ケンジ | パイロット | 35 | 火星 | 400000 |
| 3 | サクラ | 医師 | 41 | 地球 | 520000 |
| 4 | ハルト | 医師 | 33 | 月 | 450000 |
| 5 | レイ | 研究員 | 29 | 火星 | 380000 |
| 6 | ミドリ | パイロット | 27 | 地球 | 360000 |
| 7 | ソラ | エンジニア | 45 | 月 | 470000 |
| 8 | トウマ | 研究員 | 24 | NULL | 270000 |
| 9 | アカリ | エンジニア | 31 | 火星 | 350000 |
| 10 | リョウ | パイロット | 38 | NULL | 440000 |
COUNT(*)とCOUNT(列名)の違い
まずは件数です。全乗員数を数えてみましょう。
SELECT COUNT(*) FROM crew;
結果:
| COUNT(*) |
|---|
| 10 |
COUNT(*)は、値がNULLかどうかに関係なく、行そのものの数を数えます。一方、COUNT(列名)とすると、その列がNULLではない行だけを数えます。
SELECT COUNT(home) FROM crew;
結果:
| COUNT(home) |
|---|
| 8 |
トウマとリョウのhomeはNULLなので、COUNT(home)では数えられず、結果は8になります。COUNT(*)は行数、COUNT(列名)はその列にNULLではない値がある行数——この違いを押さえておきましょう。
SUM・AVG・MAX・MIN とNULLの扱い
給料に関する集計をまとめて求めてみましょう。
SELECT
SUM(salary) AS 給料合計,
AVG(salary) AS 給料平均,
MAX(salary) AS 最高給料,
MIN(salary) AS 最低給料
FROM crew;
結果:
| 給料合計 | 給料平均 | 最高給料 | 最低給料 |
|---|---|---|---|
| 3960000 | 396000 | 520000 | 270000 |
今回のcrewテーブルはsalaryにNULLの乗員がいないため、10人全員の値を使ってSUM・AVG・MAX・MINが計算されています。とはいえ集計関数には、NULLは集計の対象から自動的に除外されるという重要な性質があります。前のセクションで見たCOUNT(home)のように、もしNULLの行があれば、その行はSUMにもAVGにも一切含まれません。
もしNULLを「0円」として計算してしまったら、平均はまったく違う数字になってしまいます。NULLは0ではなく「値が分からない」という状態なので、集計関数はそれを賢く無視してくれるのです。
MAX・MINも同様に、NULLの行があれば比較の対象から外れます。文字列の列にもMAX・MINは使え、その場合は文字コード順で最大・最小が決まります。
crewテーブルに10人の乗員がいて、うちトウマとリョウの2人だけhomeがNULLです。SELECT COUNT(*), COUNT(home) FROM crew;を実行すると、結果はどうなるでしょう?
答えを見る
正解はCOUNT(*)が10、COUNT(home)が8です。COUNT(*)は行数そのものを数えるのでNULLの行も含みますが、COUNT(列名)はその列がNULLではない行だけを数えます。
集計関数を使うと、データベースに「全体としてどうなっているか」を1つの数字で答えてもらえるようになります。次回は、この集計を「グループごと」に行うGROUP BYを学びます。
/sql/game/ の SQL DIVER で、COUNT・SUM・AVG・MAX・MINを実際にタイプして試してみましょう。
集計関数のポイントはただ1つ、NULLは無視されるということ。COUNT(*)とCOUNT(列名)の違いさえ押さえれば、あとは名前の通りの働きをしてくれるよ!