CodeGym /コース /SQL SELF /集約関数を使うときによくあるミス

集約関数を使うときによくあるミス

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

さて、そろそろこれらの関数を使うときによくやりがちなミスについて深掘りしていこう。SQLガチ勢でもたまにやらかすことがあるから、俺たちのミッションはその地雷を見抜いて、うまく避けることだよ。

クエリを書いてて、なんか謎のエラー "column must appear in the GROUP BY clause or be used in an aggregate function" みたいなの出たことある?それとも、クエリの結果がなんか変で、理由が全然わからなかったことある?これ、集約関数を使うときによくあるミスの氷山の一角なんだ。このレクチャーは、そんなミスや勘違いの海で生き残るためのガイドだよ。

ミス1: GROUP BYの外で非集約カラムを使う

問題

集約データを返すクエリを書いたけど、途中でグループ化してないカラムを追加しちゃった。しかもそのカラムは集約関数で囲んでない。例えば:

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

PostgreSQLはすぐこう言ってくる:

ERROR: column "employees.salary" must appear in the GROUP BY clause or be used in an aggregate function

なんでこうなるの?

GROUP BYを使うと、PostgreSQLは指定したカラムで行をまとめる。でも、さらに別のカラム(ここではsalary)を追加すると、PostgreSQLはどう扱えばいいかわからない。1つだけのsalaryが欲しいのか、平均値なのか、それとも他の何かなのか、判断できないんだ。

どう直す?方法は2つ:

  1. 全部の非集約カラムをGROUP BYに入れる:
SELECT department, salary
FROM employees
GROUP BY department, salary;
  1. もしくは、そのカラムを集約関数で囲む(意味があるなら):
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;

アドバイス:PostgreSQLがGROUP BYで怒ってきたら、「このカラム、本当にクエリに必要?必要なら、どんな役割?」って自分に聞いてみて。

ミス2: COUNT()NULLの扱いミス

問題:社員がボーナスを入力した人数を数えたいとき、こう書く:

SELECT COUNT(bonus) AS bonus_count
FROM employees;

でも、結果が思ったより少ない。なぜ?それはCOUNT(column)columnNULLの行を無視するから。

解決策:全部の行を数えたいならCOUNT(*)を使おう:

SELECT COUNT(*) AS total_count
FROM employees;

もしくは、ボーナスがNULLじゃない行だけ数えたいなら:

SELECT COUNT(bonus) AS bonus_count
FROM employees
WHERE bonus IS NOT NULL;

ヒント:NULLが入ってるレコードと、テーブルに全くレコードがない場合の違いを意識したいなら、COUNT(*)COUNT(column)をちゃんと使い分けよう。

ミス3: HAVINGじゃなくてWHEREでフィルタしちゃう

問題:平均給与が5000を超える部署を探したい。新人エンジニアはこんな感じで書いちゃう:

SELECT department, AVG(salary) AS avg_salary
FROM employees
WHERE AVG(salary) > 5000
GROUP BY department;

PostgreSQLはこう怒る:

ERROR: aggregate functions are not allowed in WHERE clause

なぜかというと、WHEREでのフィルタはグループ化より前に実行されるから。集約関数はグループ化の後でしか使えない。つまり、AVG(salary)WHEREの時点ではまだ計算されてない。

これを直すには、集約後のデータをフィルタするHAVINGを使おう:

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

ミス4: WHEREの位置ミスと実行順序の混乱

問題:30歳以上の社員がいる部署ごとの人数を知りたい。クエリはこんな感じになりがち:

SELECT department, COUNT(*)
FROM employees
GROUP BY department
WHERE age > 30;

PostgreSQLはまた怒る:

ERROR: syntax error at or near "WHERE"

なぜ?WHEREは必ずGROUP BYより前に処理される。つまり、WHEREの位置が間違ってる。

こういう時は、まず行をフィルタしてからグループ化しよう。

SELECT department, COUNT(*)
FROM employees
WHERE age > 30
GROUP BY department;

ミス5: NULLSUM()AVG()などの関数の組み合わせ

問題:社員に支給したボーナスの合計を出したいとき、こう書く:

SELECT SUM(bonus) AS total_bonus
FROM employees;

でも、結果がやけに少ない。なぜかというと、半分の社員はボーナスが未入力で、そのNULLは無視されてるから。

解決策:NULLを事前に処理しよう。例えば、NULL0に置き換える:

SELECT SUM(COALESCE(bonus, 0)) AS total_bonus
FROM employees;

これで全部のNULLが0になって、合計が正しくなる。

COALESCEの使い方は、あと数回のレクチャーで詳しくやるよ。

ミス6: 複数の集約関数を使うときの関係性の理解不足

問題:社員の人数と給与合計を出したい。でも、こんなクエリだと変な結果になることがある:

SELECT COUNT(salary) AS count_salary, SUM(salary) AS total_salary
FROM employees;

なぜかというと、誰かのsalaryがNULLだと、COUNT(salary)SUM(salary)の結果がズレて混乱する。

集約関数はそれぞれ独立して動く。NULLがあると結果がバラバラになる。COALESCECOUNT(*)を使って一貫性を持たせよう:

SELECT COUNT(*) AS total_employees, SUM(COALESCE(salary, 0)) AS total_salary
FROM employees;

ミス7: グループ化が多すぎる非効率なクエリ

問題:グループ化のカラムが多すぎて、クエリが5分じゃなくて5時間かかる:

SELECT department, job_title, location, COUNT(*)
FROM employees
GROUP BY department, job_title, location;

グループ化する前に、本当に全部のカラムがGROUP BYに必要か考えよう。グループのユニーク値が多いほど、クエリは遅くなる。できればグループ化を減らそう:

SELECT department, COUNT(*)
FROM employees
GROUP BY department;

これらのミスはよくあることで、SQLガチ勢でもやっちゃうことがある。これで地雷を避けて、速くて正確でキレイなクエリが書けるようになるはず!

2
タスク
SQL SELF, レベル 8, レッスン 4
ロック未解除
非集約カラムの問題
非集約カラムの問題
2
タスク
SQL SELF, レベル 8, レッスン 4
ロック未解除
HAVINGによるフィルタリング
HAVINGによるフィルタリング
1
アンケート/クイズ
データのグループ化、レベル 8、レッスン 4
使用不可
データのグループ化
データのグループ化
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION