SQLの集計関数とGROUP BY句:データ分析の基本をマスター
データ集計の第一歩:集計関数とは?
データベースに蓄積された大量のデータから、特定の情報を抜き出したい、あるいは全体像を把握したいと思ったことはありませんか?
例えば、ECサイトの売上データから「今月どれだけの売上があったのか?」を知りたい場合や、会員リストから「何人の会員がいるのか?」を知りたい場合などです。
このような「集計」を行いたいときに活躍するのが、SQLの集計関数です。
集計関数は、複数の行から一つの値を計算して返す特別な関数です。
SQLには、主に以下の5つの集計関数があります。
- SUM(): 指定した列の合計値を計算します。
- AVG(): 指定した列の平均値を計算します。
- COUNT(): 行数を数えます。
- MAX(): 指定した列の最大値を返します。
- MIN(): 指定した列の最小値を返します。
これらの関数を使うことで、複雑な計算をSQLに任せることができ、データ分析の効率が格段に向上します。
SUM()関数:合計値を計算する
まず、最も基本的なSUM()関数から見ていきましょう。
SUM()関数は、指定した列のすべての値の合計を計算します。
例えば、ordersテーブルに格納されている注文金額を合計して、総売上を求めたいとします。
SELECT SUM(amount) AS total_sales FROM orders;
このクエリは、ordersテーブルのamount列(注文金額)の合計を計算し、total_salesという別名で結果を表示します。
もし、productsテーブルに格納されている商品の価格の合計を知りたい場合は、以下のように書けます。
SELECT SUM(price) AS total_product_value FROM products;
SUM()関数は数値型の列に対してのみ使用できます。
AVG()関数:平均値を計算する
次に、AVG()関数です。
AVG()関数は、指定した列の平均値を計算します。
例えば、studentsテーブルに登録されている生徒たちのテストの点数から、クラス全体の平均点を求めたいとします。
SELECT AVG(score) AS average_score FROM students;
このクエリは、studentsテーブルのscore列(点数)の平均値を計算し、average_scoreという別名で表示します。
AVG()関数も、SUM()関数と同様に数値型の列に対して使用します。
COUNT()関数:行数を数える
COUNT()関数は、指定した条件に合致する行の数を数えるのに非常に便利です。
COUNT()関数には、いくつかの使い方があります。
COUNT(*): テーブル全体の行数(レコード数)を数えます。COUNT(column_name): 指定した列にNULL以外の値を持つ行数を数えます。COUNT(DISTINCT column_name): 指定した列のユニーク(一意)な値の数を数えます。
例を見てみましょう。
usersテーブルに登録されている全ユーザー数を数えたい場合:
SELECT COUNT(*) AS total_users FROM users;
productsテーブルで、価格がNULLではない商品の数を数えたい場合:
SELECT COUNT(price) AS count_products_with_price FROM products;
ordersテーブルで、ユニークな顧客IDの数を数えたい場合(つまり、何人の異なる顧客が注文したかを知りたい場合):
SELECT COUNT(DISTINCT customer_id) AS distinct_customers FROM orders;
COUNT()関数は、データ件数の把握に不可欠です。
MAX()関数とMIN()関数:最大値・最小値を取得する
MAX()関数とMIN()関数は、それぞれ指定した列の最大値と最小値を返します。
例えば、productsテーブルで最も高い商品の価格を知りたい場合:
SELECT MAX(price) AS highest_price FROM products;
最も安い商品の価格を知りたい場合:
SELECT MIN(price) AS lowest_price FROM products;
これらの関数は、データの範囲を把握するのに役立ちます。
例えば、employeesテーブルで最も給与が高い社員の給与額や、最も給与が低い社員の給与額を知りたい場合にも使えます。
SELECT MAX(salary) AS highest_salary, MIN(salary) AS lowest_salary FROM employees;
複数のグループに分けて集計する:GROUP BY句
ここまでは、テーブル全体のデータを対象に集計関数を使ってきました。
しかし、実際のデータ分析では、「部門ごとの売上」や「商品カテゴリごとの平均価格」のように、データを特定の基準でグループ分けして集計したい場面が頻繁にあります。
そのような場合に使うのがGROUP BY句です。
GROUP BY句は、指定した列の値が同じ行を一つのグループにまとめ、そのグループごとに集計関数を適用します。
GROUP BY句の基本的な使い方
例えば、ordersテーブルから、顧客IDごとに注文金額の合計を求めたいとします。
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id;
このクエリは、まずcustomer_idの値でグループ化します。
そして、各customer_idグループに対して、SUM(amount)を実行し、その顧客が支払った合計金額を計算します。
結果として、各顧客IDとその顧客の総注文金額のリストが得られます。
次に、productsテーブルで、商品カテゴリ(category)ごとに平均価格(price)を求めたい場合を考えてみましょう。
SELECT category, AVG(price) AS average_price_per_category
FROM products
GROUP BY category;
このクエリは、productsテーブルをcategory列の値でグループ化し、各カテゴリの平均価格を計算します。
SELECT句とGROUP BY句の組み合わせにおける注意点
GROUP BY句を使用する際には、SELECT句に含めることができる列について、いくつか注意点があります。
SELECT句には、以下のいずれかの列しか含めることができません。
GROUP BY句で指定した列: 上記の例でいうとcustomer_idやcategoryのような列です。- 集計関数で計算された結果:
SUM(amount)やAVG(price)のような集計関数の結果です。
もし、GROUP BY句で指定していない、集計関数でも処理されていない列をSELECT句に含めようとすると、多くの場合エラーになります。
なぜなら、GROUP BY句でグループ化された各グループは、本来複数の行を含んでいる可能性があるため、その中からどの行の値を表示すれば良いかSQLが判断できないからです。
例えば、以下のクエリはエラーになる可能性が高いです。
-- これはエラーになる可能性が高い例
SELECT customer_id, order_date, SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id;
この場合、同じcustomer_idを持つ注文が複数あると、それらのorder_dateはそれぞれ異なる可能性があります。
SQLは、このcustomer_idグループ全体に対して、どのorder_dateを表示すべきか決定できません。
どうしてもグループ化されたデータに対して、グループ内の特定の行の情報(例えば、最新の注文日など)を表示したい場合は、HAVING句やウィンドウ関数、サブクエリなどを組み合わせる必要があります。
HAVING句:グループ化された結果をさらに絞り込む
WHERE句は、集計関数が実行される前に、個々の行をフィルタリングします。
一方、HAVING句は、GROUP BY句によってグループ化された後のグループに対してフィルタリングを行います。
例えば、総注文金額が10000円以上の顧客のみを表示したい場合、HAVING句を使います。
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING SUM(amount) >= 10000;
このクエリは、まず全顧客の総注文金額を計算し、その結果から総注文金額が10000以上であるグループのみを抽出します。
WHERE句とHAVING句の違いを理解することは、複雑なデータ集計を行う上で非常に重要です。
集計関数とGROUP BY句の応用
集計関数とGROUP BY句を組み合わせることで、より高度なデータ分析が可能になります。
複数列でのグループ化
GROUP BY句には、複数の列を指定することもできます。
例えば、salesテーブルで、product_category(商品カテゴリ)ごと、かつsale_date(販売日)ごとに売上金額(amount)の合計を求めたい場合です。
SELECT product_category, sale_date, SUM(amount) AS daily_sales_by_category
FROM sales
GROUP BY product_category, sale_date
ORDER BY product_category, sale_date;
このクエリは、まずproduct_categoryとsale_dateの組み合わせでグループ化し、各組み合わせごとの合計売上を計算します。
ORDER BY句で結果をソートすることで、見やすい形式で表示できます。
COUNT(DISTINCT)の活用
COUNT(DISTINCT column_name)は、特定のグループ内でユニークな値の数を数えるのに役立ちます。
例えば、ordersテーブルで、商品カテゴリ(product_category)ごとに、いくつの異なる商品が注文されたかを数えたい場合です。
SELECT product_category, COUNT(DISTINCT product_id) AS distinct_products_ordered
FROM orders
GROUP BY product_category;
これにより、各カテゴリでどれだけ多様な商品が購入されているかの傾向を把握できます。
集計関数とNULL値
集計関数は、NULL値をどのように扱うかを知っておくことが重要です。
SUM(),AVG(),MAX(),MIN(): これらの関数は、NULL値を無視して計算します。COUNT(column_name): NULL値はカウントしません。COUNT(*): NULL値も含めてすべての行をカウントします。
例えば、productsテーブルで、価格(price)がNULLの商品がある場合、AVG(price)はそのNULL値を除いた商品の平均価格を計算します。
もし、NULLを0として扱いたい場合は、COALESCE()関数などを使って事前にNULLを置換する必要があります。
SELECT AVG(COALESCE(price, 0)) AS average_price_including_nulls
FROM products;
このように、集計関数とGROUP BY句は、SQLを使ったデータ集計と分析の基本となります。
これらの機能をマスターすることで、データから価値ある洞察を引き出すための強力な武器を手に入れることができるでしょう。
データ分析の旅は、ここから始まります。
SQL Questでは、これらの概念をさらに深めるための練習問題も豊富に用意しています。ぜひ、次のステップに進んでみてください。
関連練習問題
集計関数とGROUP BY句の理解を深めるために、以下の練習問題に挑戦してみましょう。
- 商品別注文件数 (intermediate-2)
- ユーザー別総注文金額 (intermediate-3)
- カテゴリ別平均価格 (intermediate-5)
- 月別売上合計 (intermediate-13)