MySQL 入門

MySQL 集約関数

データベースからデータを取得する際、個々の行(レコード)をそのまま表示するだけでなく、複数のレコードを要約・集約して情報を抽出したい場面が多々あります。ここで活用されるのが集約関数(Aggregate Functions)です。これらは一連のレコードに対して計算を行い、単一の値を返します。集約関数を使いこなすことで、データセットに対する深いインサイトを得ることが可能になります。

1. COUNT:レコード数のカウント

COUNT() 関数はその名の通り、数を数えるために使用されます。テーブルの全レコード数、特定の条件を満たすレコード数、さらには特定のカラム(列)内の非NULL値の数などをカウントできます。

1.1 全レコードのカウント

テーブルに何行のデータがあるかを確認するには、COUNT(*) を使用します。

-- city(都市)テーブル内の全レコード数をカウント
SELECT COUNT(*) FROM city;

このクエリは、カラムの値に関係なく、city テーブル内の総都市数を表す数値を返します。

1.2 WHERE 句を使用した特定レコードのカウント

特定の条件に一致するレコードのみをカウントしたい場合は、COUNT(*)WHERE 句を組み合わせます。

-- アメリカ(USA)に位置する都市の数をカウント
SELECT COUNT(*) FROM city WHERE CountryCode = 'USA';

これにより、CountryCode が 'USA' であるレコードがいくつあるかがわかります。

1.3 カラム内の非NULL値のカウント

特定のカラムに NULL ではない値がいくつ含まれているかを知りたい場合は、COUNT(カラム名) を使用します。COUNT(*) とは異なり、COUNT(カラム名) はそのカラムの値が NULL であるレコードを無視します。

例えば、city テーブルに District(行政区)というカラムがあり、一部の都市で District が指定されていない(NULL である)と仮定します。

-- インド(IND)の都市の中で、Districtが設定されているレコード数をカウント
SELECT COUNT(District) FROM city WHERE CountryCode = 'IND';

このクエリは、インドの都市のうち District カラムに値が入っているものだけをカウントします。もしインドの都市で DistrictNULL のレコードがあれば、それはカウントから除外されます。

重要な違い: COUNT(*)NULL 値を含むすべての行をカウントしますが、COUNT(カラム名) はそのカラムが NULL ではない行のみをカウントします。

1.4 重複を除外したカウント

カラム内に存在する「一意な(ユニークな)値」の数を知りたい場合があります。例えば、city テーブルにはいくつの異なる国が含まれているでしょうか?これには COUNT(DISTINCT カラム名) を使用します。

-- cityテーブルに登録されている、重複を除いた国の総数をカウント
SELECT COUNT(DISTINCT CountryCode) FROM city;

このクエリは CountryCode カラムをスキャンし、各コードを一度だけカウントすることで、リストアップされた国の総数を算出します。

2. SUM:数値の合計計算

SUM() 関数は、数値型のカラムの合計値を計算します。国の総人口や、大陸の総面積などの「総計」を求める際に非常に便利です。

アメリカのすべての都市の総人口を求めてみましょう。

-- アメリカ(USA)の全都市の人口合計を算出
SELECT SUM(Population) FROM city WHERE CountryCode = 'USA';

このクエリは、CountryCode が 'USA' であるすべての都市の Population(人口)の合計値を返します。一致するレコードがない場合、SUM()NULL を返します。また、数値型ではないデータに対して実行するとエラーが発生します。

3. AVG:平均値の計算

AVG() 関数は、数値型のカラムの平均値(算術平均)を計算します。SUM() と同様に、計算時に NULL 値は無視されます。

日本(JPN)の都市の平均人口を確認するには以下のように記述します。

-- 日本の都市の平均人口を算出
SELECT AVG(Population) FROM city WHERE CountryCode = 'JPN';

これにより、日本の都市の平均人口が得られます。もし人口データが NULL の都市があれば、そのレコードは平均値の計算から除外されます。

4. MIN と MAX:極値の抽出

MIN() 関数と MAX() 関数は、それぞれ指定したカラムから「最小値」と「最大値」を取得します。これらは数値だけでなく、文字列や日付/時刻型のカラムにも使用可能です。

4.1 最小値の検索

フランスの都市の中で、最も人口が少ない都市の人口数を探します。

-- フランス(FRA)の都市における最小の人口数を取得
SELECT MIN(Population) FROM city WHERE CountryCode = 'FRA';

4.2 最大値の検索

中国の都市の中で、最も人口が多い都市の人口数を探します。

-- 中国(CHN)の都市における最大の人口数を取得
SELECT MAX(Population) FROM city WHERE CountryCode = 'CHN';

4.3 数値以外のデータに対する MIN/MAX の使用

MIN()MAX() は、アルファベット順での最初・最後の文字列、あるいは最も古い・新しい日付を探す際にも有効です。

city テーブルから、アルファベット順で最初と最後にくる都市名を検索してみましょう。

-- アルファベット順で最初(MIN)と最後(MAX)の都市名を取得
SELECT MIN(Name), MAX(Name) FROM city;

これにより、辞書順で先頭にくる名前と、末尾にくる名前が得られます。

5. 集約関数の組み合わせ

単一の SELECT ステートメントで、複数の集約関数を同時に使用することができます。

-- ブラジル(BRA)の都市に関する各種統計を一括取得
SELECT 
    COUNT(*) AS NumberOfCities,          -- 都市数
    SUM(Population) AS TotalPopulation,   -- 総人口
    AVG(Population) AS AveragePopulation, -- 平均人口
    MIN(Population) AS SmallestPopulation,-- 最小人口
    MAX(Population) AS LargestPopulation  -- 最大人口
FROM city 
WHERE CountryCode = 'BRA';

このクエリはブラジルの全都市について5つの異なる集約値を計算し、一つの結果レコードとして概要を提示します。AS キーワードを使用して出力カラムに別名(エイリアス)を付けることで、結果がより読みやすくなります。

6. 集約関数に関する重要な注意事項

  • NULL 値の扱い: COUNT(*) を除くすべての集約関数は、操作対象のカラム内の NULL 値を無視します。例えば、SUM(カラム名)NULL に遭遇すると、それをスキップして非NULL値のみを加算します。もしカラム内のすべての値が NULL である場合、SUM()AVG()MIN()MAX()NULL を返し、COUNT(カラム名)0 を返します。
  • 独立したカラムとの混在不可: GROUP BY 句(後述)を使用せずに集約関数を使用する場合、SELECT リストには集約関数またはリテラル値(固定値)しか含めることができません。集約関数と集約されていない通常のカラム名を同じ SELECT リストに混在させることはできません。集約関数は結果セット全体に対して単一の値を返すのに対し、通常のカラムは複数の値を返そうとするため、矛盾が生じるからです。
-- 誤った例(エラーが発生します)
SELECT Name, COUNT(*) FROM city;

MySQLがすべての都市をカウントする場合、どの具体的な Name を表示すべきか判断できないため、エラーとなります。

  • DISTINCT キーワード: DISTINCTCOUNT() で最も頻繁に使われますが、SUM()AVG()MIN()MAX() の内部でも使用可能です。例えば SUM(DISTINCT Population) は重複を除いたユニークな人口数値のみを合計しますが、実務でこのような処理が必要になるケースは極めて稀です。

これらの関数は、SQLにおけるデータ分析の基礎となります。膨大な生データを意味のある指標に凝縮し、データセット内のトレンド、合計、極値を容易に把握できるようにします。