SQLite | ゼロからはじめるSQL、30日で習得するSQLite:検索力強化 - Day11 集計②

SQL SQLite
スポンサーリンク

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 円があるせいで平均が引き上げられているだけです。

ここで必要になるのが、MAXMIN です。


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 でもう一度整理します。

  1. まず、集計で全体像と極端な値を見る
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
  1. 「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 / MINWHERE の組み合わせで書けます。


Day11 後半のまとめ

平均だけを見ると、極端な値にだまされることがある。
AVG / MAX / MIN をセットで見ることで、「レンジ」と「ばらつき」が見える。
WHERE と組み合わせることで、「特定ユーザー」「特定期間」の性格を数字でつかめる。
極端に大きい値・小さい値は、バグ・不正・攻撃のサインになり得る。
数字で違和感を見つけてから、行として掘る、という流れがとても実務的。

ここまで来たあなたは、
「行をそのまま見る」「COUNT / SUM で全体を見る」に加えて、
「AVG / MAX / MIN で“データの性格”を探る」視点も手に入れています。
次のステップでは、GROUP BY を使って「ユーザーごと」「日付ごと」などのグループ単位で、これらの集計を一気に出していく世界に進んでいきます。

タイトルとURLをコピーしました