Day11 後半
「平均だけ見ない」ために、AVG / MAX / MIN をセットで使う
前半で、AVG / MAX / MIN を単体で使う感覚はつかめました。
後半では、それらをセットで使う意味と、もう少し実務寄りの問いにどう落とし込むかを見ていきます。
キーワードは、
「平均だけを信じない」
「極端な値を一緒に見る」
です。
平均だけを見る危うさ
「1人だけ極端に大きい人」が平均を引き上げてしまう
まず、極端な例で「平均の危うさ」を体感してみましょう。
次のような orders テーブルを考えます。
id | user_id | amount
---+---------+-------
1 | 1 | 1000
2 | 2 | 1200
3 | 3 | 1100
4 | 4 | 900
5 | 5 | 100000
1〜4件目は 1000 円前後ですが、5件目だけ 100,000 円という極端な値が入っています。
ここで、平均購入金額を出してみます。
SELECT AVG(amount) FROM orders;
SQL計算すると、
1000 + 1200 + 1100 + 900 + 100000 = 104200
104200 ÷ 5 = 20840
結果はだいたいこうなります。
AVG(amount)
-----------
20840.0
「平均 20,840 円」と言われると、
「このサイト、1件あたり2万円くらい売れてるのか、すごいな」と錯覚しそうになります。
でも実際には、
ほとんどの注文は 1,000 円前後で、
1件だけ 100,000 円があるせいで平均が引き上げられているだけです。
ここで必要になるのが、MAX と MIN です。
AVG / MAX / MIN をセットで見る
「レンジ」と「ばらつき」をざっくりつかむ
同じテーブルに対して、3つまとめて聞いてみます。
SELECT
AVG(amount) AS avg_amount,
MAX(amount) AS max_amount,
MIN(amount) AS min_amount
FROM orders;
SQL結果のイメージはこうです。
avg_amount | max_amount | min_amount
-----------+------------+----------
20840.0 | 100000 | 900
この3つを並べて見ると、
平均は 20,840 円
でも、最小は 900 円、最大は 100,000 円
という「レンジの広さ」が一目で分かります。
ここでのポイントは、
平均だけを見ると「普通っぽく」見えてしまうものも、
最大・最小を一緒に見ると「極端な値が混ざっている」ことに気づける、ということです。
WHERE と組み合わせて「一部の世界」の性格を見る
「特定ユーザー」「特定期間」に絞ってから集計する
前半でも触れましたが、WHERE と組み合わせると、
「全体」ではなく「一部」の性格を数字で見ることができます。
たとえば、「2025-04-01 の注文だけに絞って、平均・最大・最小を見たい」とします。
SELECT
AVG(amount) AS avg_amount,
MAX(amount) AS max_amount,
MIN(amount) AS min_amount
FROM orders
WHERE date(created_at) = '2025-04-01';
SQLあるいは、「user_id = 1 のユーザーの注文だけ」に絞るならこうです。
SELECT
AVG(amount) AS avg_amount,
MAX(amount) AS max_amount,
MIN(amount) AS min_amount
FROM orders
WHERE user_id = 1;
SQLここで意識してほしいのは、
「どの世界を切り出して、その中の性格を見たいのか」
を WHERE で決めてから、AVG / MAX / MIN でその世界の「平均」「上限」「下限」を見る、という流れです。
アクセスログで考える実務寄りの例
「1日の平均アクセス数」「最大アクセス数」を見る
もう少し現場っぽい例として、access_logs テーブルを考えます。
id | user_id | path | created_at
---+---------+---------- +-------------------
1 | 1 | /login | 2025-04-01 10:00
2 | 2 | /products | 2025-04-01 10:01
...
ここに、日ごとのアクセス件数を集計した結果が、別テーブル daily_access に入っているとします。
date | count
-----------+------
2025-03-28 | 1200
2025-03-29 | 1300
2025-03-30 | 1250
2025-03-31 | 8000
2025-04-01 | 1400
この daily_access に対して、
「1日あたりの平均アクセス数」
「1日あたりの最大アクセス数」
「1日あたりの最小アクセス数」
を見てみます。
SELECT
AVG(count) AS avg_count,
MAX(count) AS max_count,
MIN(count) AS min_count
FROM daily_access;
SQL結果のイメージはこうです。
avg_count | max_count | min_count
----------+-----------+---------
2630.0 | 8000 | 1200
ここで、
平均は 2630
でも、最大は 8000(明らかに他の日より多い)
ということが分かります。
この「8000 の日」は、
キャンペーンでアクセスが増えたのか、
攻撃やバグで異常に増えたのか、
調査すべき“怪しい日”として浮かび上がります。
セキュリティの視点から見る「極端な値」
「MAX が教えてくれる“おかしな一発”」
セキュリティの現場では、
「平均」よりも「極端な一発」の方が重要なことが多いです。
1件だけ異常に大きい購入金額
1日だけ異常に多いアクセス数
1ユーザーだけ異常に多いログイン試行回数
こうしたものは、MAX を見ることで浮かび上がります。
逆に、MIN も役に立ちます。
金額が 0 やマイナスになっていないか
アクセス数が 0 の日がないか(システム停止の可能性)
など、「ありえないほど小さい値」も異常のサインです。
ここで大事なのは、
「AVG / MAX / MIN は、“普通の姿”と“おかしな姿”の両方を数字で教えてくれる」
という視点です。
「行を見る」と「数字で見る」を行き来する流れをもう一度
まず数字で違和感を見つけてから、行で掘る
Day10 でもやった流れを、AVG / MAX / MIN でもう一度整理します。
- まず、集計で全体像と極端な値を見る
SELECT
AVG(amount) AS avg_amount,
MAX(amount) AS max_amount,
MIN(amount) AS min_amount
FROM orders
WHERE date(created_at) = '2025-04-01';
SQL- 「MAX がやたら大きいな」と思ったら、その原因となっていそうな行を掘る
SELECT * FROM orders
WHERE date(created_at) = '2025-04-01'
ORDER BY amount DESC
LIMIT 10;
SQLこの流れは、
数字で「何かおかしいぞ?」と気づく
→ 行として「どのレコードがそれを生んでいるのか」を特定する
という、とても実務的なパターンです。
小さな練習で締める
日本語の問いを、AVG / MAX / MIN に翻訳してみる
頭の中で、次の問いを SQL にしてみてください。
全注文の平均購入金額・最大購入金額・最小購入金額を知りたい。
user_id = 2 のユーザーの平均購入金額・最大購入金額を知りたい。
1日あたりのアクセス数の平均・最大・最小を知りたい(daily_access テーブルがある前提)。
全部、AVG / MAX / MIN と WHERE の組み合わせで書けます。
Day11 後半のまとめ
平均だけを見ると、極端な値にだまされることがある。
AVG / MAX / MIN をセットで見ることで、「レンジ」と「ばらつき」が見える。
WHERE と組み合わせることで、「特定ユーザー」「特定期間」の性格を数字でつかめる。
極端に大きい値・小さい値は、バグ・不正・攻撃のサインになり得る。
数字で違和感を見つけてから、行として掘る、という流れがとても実務的。
ここまで来たあなたは、
「行をそのまま見る」「COUNT / SUM で全体を見る」に加えて、
「AVG / MAX / MIN で“データの性格”を探る」視点も手に入れています。
次のステップでは、GROUP BY を使って「ユーザーごと」「日付ごと」などのグループ単位で、これらの集計を一気に出していく世界に進んでいきます。
