CodeGym /コース /SQL SELF /HAVINGで集約データをフィルタリングする

HAVINGで集約データをフィルタリングする

SQL SELF
レベル 8, レッスン 1
使用可能

まだ話してなかったことがあるんだ。それは集約した後のグループをどうやってフィルタリングするか?ってこと。全部の学部が欲しいわけじゃなくて、例えば学生が100人以上いる学部だけ知りたいとか、平均給料が50,000より高い部署だけ見たいとか。今日はHAVINGを使って集約データをフィルタリングする方法を紹介するよ。

HAVINGってなんで必要なの?WHEREがあるじゃん?GROUP BYの後にWHERE置けばいいんじゃない? :)

そんなに単純じゃないんだ!まず、SQLの構文の順番は決まってて、WHEREはGROUP BYより前に実行されるんだよ。

じゃあ、GROUP BYの後にWHEREを置けないの?

それもダメ!よくあるのは、まずテーブルの行をフィルタしてからグループ化して、その後でグループごとにいらないデータを捨てたいってパターン。

じゃあ、WHEREをコピーして、名前をHAVINGにしてGROUP BYの後に置けばいいんじゃない?

そうそう、それでOK! :)

HAVINGとWHEREの違い

WHEREはグループ化する前の行をフィルタする。

例えば、ケーキを味で選ぶとき:いちご味とチョコ味だけ残して、他はスルー。これがWHEREの役割。

HAVINGはデータをグループ化して集約関数が動いた後でフィルタする。

例えば、もうケーキをテーブルごとにグループ化して数を数えた後、ケーキが3個以上あるテーブルだけ残したいとき。

つまり、HAVINGはグループ単位でデータをフィルタするために使うんだ。

HAVINGの構文

構文はほぼWHEREと同じだけど、動きがちょっと違う:

SELECT カラム, 集約関数
FROM テーブル
GROUP BY カラム
HAVING 条件;

実行の流れ:

  1. まずWHEREで行をフィルタする。
  2. 次にGROUP BYでデータをグループ化。
  3. グループ化した結果に集約関数を適用。
  4. 最後にHAVINGでグループをフィルタする。

HAVINGの使い方例

例1: 学生数が多い学部をフィルタ

大学で学生が100人以上いる学部を知りたいとする。テーブルstudentsがあるとしよう:

id name faculty
1 Alice Engineering
2 Bob Engineering
3 Charlie Arts
4 Daisy Business
5 ... ...

クエリ:

SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;

何が起きてるか:

  • まずGROUP BYでfacultyごとに学生をグループ化。
  • 次に集約関数COUNT(*)で各学部の学生数を数える。
  • 最後にHAVINGで学生が100人以下の学部を除外。

結果:

faculty student_count
Engineering 150
Arts 120

例2: 平均給料が高い部署

平均給料が50,000を超える部署だけ知りたいとき。テーブルemployeesがあるとする:

id name department salary
1 Alice IT 60000
2 Bob HR 45000
3 Charlie IT 70000
4 Daisy HR 52000
5 ... ... ...

クエリ:

SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;

結果:

department avg_salary
IT 65000

ポイント:HAVINGはGROUP BYの後で計算された結果に対して動くよ。

WHERE, GROUP BY, HAVINGの実行順序

WHEREとHAVINGのフィルタは違うタイミングで実行される。違いをもっと理解するために、クエリの流れを見てみよう:

  1. WHERE: 行のフィルタ。

    この段階でテーブルの全行が処理される。WHEREの条件に合わない行はこの時点で消える。

  2. GROUP BY: 行のグループ化。

    フィルタ後の行がGROUP BYで指定したカラムごとにまとめられる。

  3. 集約関数:

    グループ化したデータにCOUNT()、AVG()、SUM()などの集約関数を適用。

  4. HAVING: グループのフィルタ。

    この段階では集約結果だけが処理される。HAVINGの条件はグループにだけ適用される。

HAVINGの特徴

特徴1: 集約関数との連携

HAVINGとWHEREの一番の違いは、集約関数と一緒に使えること。例えば:

SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;

このクエリではAVG(salary)はWHEREの中では使えない。なぜならWHEREはグループ化前の行にしか使えないから。こんなクエリ:

SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;

はエラーになる:aggregate functions are not allowed in WHERE。

特徴2: グループ化なしでも使える

HAVINGはGROUP BYがなくても使える。この場合、全レコードが1つのグループとして扱われる:

SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;

実践例

例えば、ショップがあって、売上テーブルsalesがあるとする:

id product_id sales_amount
1 101 200.00
2 102 300.00
3 101 400.00
4 103 150.00

クエリ:合計売上が500を超える商品を探す。

SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;

結果:

product_id total_sales
101 600.00

よくあるミス

WHEREで集約関数を使う:

例えば:

SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;

エラー:WHEREで集約関数は使えない。

NULLに関するミス:

データにNULLがあると、フィルタ結果が予想外になることがある。例えば:

SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;

salaryカラムが全部NULLだと、結果が0や空になることがある。

おめでとう!これで集約データのフィルタもバッチリできるようになったね!HAVINGはグループ単位の分析のカギだから、普通のWHEREじゃ足りないときはぜひ使ってみて!

2
タスク
SQL SELF, レベル 8, レッスン 1
ロック未解除
2人以上の学生がいる学部での学生のフィルタリング
2人以上の学生がいる学部での学生のフィルタリング
2
タスク
SQL SELF, レベル 8, レッスン 1
ロック未解除
総売上額による商品のフィルタリング
総売上額による商品のフィルタリング
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION