SQL / LESSON 06 / SQL06

SQL:集計関数(COUNT / SUM / AVG)

1学習の目的

2基礎解説

ここまでは行を取り出すだけでした。集計関数を使うと、複数の行を1つの値にまとめられます

関数意味NULLの扱い
COUNT(*)行数NULLの行も数える
COUNT(列)その列の入力済み件数NULLは除く
SUM(列) / AVG(列)合計 / 平均NULLは無視される
MIN(列) / MAX(列)最小 / 最大NULLは無視される
✅ 覚えるべき重要ポイント
  1. 集計関数は結果が1行になる。5行でも1万行でも、返ってくるのは1行だけ。
  2. AVG の分母はNULLを除いた件数。7行のうち1行がNULLなら、6で割られる。「NULLを0とみなして7で割る」のとは答えが変わる——どちらが正しいかは業務の定義次第。
  3. COUNT(*)COUNT(列名) は別物(SQL05)。全行を数えたいのか、入力済みを数えたいのかで使い分ける。
  4. COUNT(DISTINCT 列)重複を除いた種類数が数えられる。「何種類のカテゴリがあるか」を1行で出せる。
  5. 集計関数の中には計算式も書けるSUM(price * stock) で在庫総額が一発で出る。

現場使用例:今月の売上合計、会員数、平均単価、最高購入額、商品カテゴリの種類数。レポートの数字はほぼすべて集計関数から生まれる

-- 行数を数える
SELECT COUNT(*) AS 件数 FROM products;        -- 7

-- 合計と平均
SELECT
  SUM(price) AS 合計,      -- 211200
  AVG(price) AS 平均       -- 35200.0
FROM products;

-- ⚠ AVG の分母はNULLを除いた6件
SELECT
  SUM(price)            AS 合計,        -- 211200
  COUNT(price)          AS 分母,        -- 6(7ではない)
  AVG(price)            AS 平均,        -- 35200.0
  AVG(COALESCE(price,0)) AS 平均0埋め    -- 30171.4…(分母7)
FROM products;

-- 最小・最大
SELECT MIN(price) AS 最安, MAX(price) AS 最高 FROM products;

-- 絞り込んでから集計する
SELECT COUNT(*) AS 件数, SUM(price) AS 合計
FROM products
WHERE category = '周辺機器';

-- 計算式もまとめて集計できる
SELECT SUM(price * stock) AS 在庫総額 FROM products;

3基本ドリル(10問)

SQL06-D01 products テーブルの行数を「件数」という別名で取り出すSQLを書け。 コーディング★☆☆無料
期待される結果

1行。件数 7

ヒント

COUNT(*) を使う。AS で別名を付ける。

模範解答
SELECT COUNT(*) AS 件数
FROM products;
解説

集計関数は結果が1行になる。7行のテーブルから返るのは「7」という1つの値だけ。

SQL06-D02 集計関数を使ったとき、結果は何行になるか。
A. 元の行数と同じ B. 1行 C. 0行 D. 条件による
選択★☆☆無料
期待される結果

解答 == B

ヒント

「まとめる」という言葉の意味。

模範解答
B
解説

複数の行を1つの値に集約するのが集計関数。次章の GROUP BY を使うと、グループごとに1行ずつ返るようになる。

SQL06-D03 price の合計を「合計」、平均を「平均」という別名で取り出すSQLを書け。 コーディング★☆☆無料
期待される結果

1行。合計 211200 / 平均 35200.0

ヒント

SUM(price) と AVG(price) をカンマで並べる。

模範解答
SELECT SUM(price) AS 合計, AVG(price) AS 平均
FROM products;
解説

複数の集計を1回のSQLで取れる。合計と平均を別々に問い合わせる必要はない。

SQL06-D04 price の最高値を取り出すSQLを完成させよ。 穴埋め★☆☆無料
コード
SELECT ____(price) AS 最高
FROM products;
期待される結果

1行。最高 128000

ヒント

「最大」を意味する3文字の関数。

模範解答
MAX
解説

対になるのは MIN文字列にも使えるので、名前の五十音順で最初・最後を取ることもできる。

SQL06-D05 7行のうち price が1行NULLのとき、AVG(price) の分母はいくつか。
A. 7 B. 6 C. 1 D. 0
選択★☆☆無料
期待される結果

解答 == B

ヒント

AVG はNULLをどう扱うか。

模範解答
B
解説

NULLは無視されるので分母は6。「未入力を0として7で割る」のとは答えが変わる。どちらが正しいかは業務の定義次第で、SQLが決めることではない。

SQL06-D06 category の種類数(重複を除いた数)を「分類数」という別名で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

1行。分類数 2

ヒント

COUNT(DISTINCT category) と書く。

模範解答
SELECT COUNT(DISTINCT category) AS 分類数
FROM products;
解説

DISTINCT はNULLも除くので、NULLのカテゴリは種類に数えられない。結果は「PC」「周辺機器」の2種類。

SQL06-D07 在庫総額(price × stock の合計)を取り出すSQLを完成させよ。 穴埋め★★☆無料
コード
SELECT ____(price * stock) AS 在庫総額
FROM products;
期待される結果

1行。在庫総額 1422400

ヒント

「合計」を意味する3文字の関数。

模範解答
SUM
解説

集計関数の中に計算式を書ける。各行で price × stock を計算してから、それらを合計している。

SQL06-D08 該当する行が1件も無いとき SUM(price) は何を返すか。
A. 0 B. NULL C. エラー D. 空文字
選択★★☆無料
期待される結果

解答 == B

ヒント

「合計すべき値が存在しない」状態。

模範解答
B
解説

0ではなくNULLが返るのが要注意。画面に表示する前に COALESCE(SUM(price), 0) で0に置き換えるのが実務の定石。

SQL06-D09 category が '周辺機器' の商品について、件数(別名「件数」)と price の合計(別名「合計」)を取り出すSQLを書け。 コーディング★★☆無料
期待される結果

1行。件数 4 / 合計 13200

ヒント

WHERE で絞ってから集計する。句の順番は FROM → WHERE。

模範解答
SELECT COUNT(*) AS 件数, SUM(price) AS 合計
FROM products
WHERE category = '周辺機器';
解説

絞り込んでから集計するのが基本。件数は4件だが、そのうち1件はpriceがNULLなので合計には3件分しか入っていない。

SQL06-D10 price の平均を小数第1位まで四捨五入して「平均単価」という別名で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

1行。平均単価 35200.0

ヒント

ROUND(値, 桁数) を使う。ROUND(AVG(price), 1) のように入れ子にできる。

模範解答
SELECT ROUND(AVG(price), 1) AS 平均単価
FROM products;
解説

AVG の結果は小数が長くなりがちなので、レポートでは ROUND で桁を揃える。関数は入れ子にできる。

4実践シナリオ(5問)

SQL06-S01 【マスタの状況把握】次の3つを1行で取り出すSQLを書け。
① 全商品数(別名「全商品」)② 価格が入力済みの件数(別名「価格あり」)③ カテゴリの種類数(別名「分類数」)
コーディング★★☆無料
期待される結果

1行。7 / 6 / 2

ヒント

COUNT(*)、COUNT(price)、COUNT(DISTINCT category) を並べる。

模範解答
SELECT
  COUNT(*) AS 全商品,
  COUNT(price) AS 価格あり,
  COUNT(DISTINCT category) AS 分類数
FROM products;
解説

3種類の COUNT を使い分けている。全体・入力済み・種類数はそれぞれ別の情報で、テーブルを初めて見るときの基本調査になる。

SQL06-S02 【価格帯の把握】price について、最安値(別名「最安」)・最高値(別名「最高」)・平均(別名「平均」、小数第1位まで)を1行で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

1行。1500 / 128000 / 35200.0

ヒント

MIN・MAX・ROUND(AVG(...), 1) を並べる。

模範解答
SELECT
  MIN(price) AS 最安,
  MAX(price) AS 最高,
  ROUND(AVG(price), 1) AS 平均
FROM products;
解説

最小・最大・平均の3つでデータの分布が見える。平均だけでは「高い商品と安い商品が混在しているのか」が分からない。

SQL06-S03 【カテゴリ別の集計】category が 'PC' の商品について、件数(別名「件数」)・合計金額(別名「合計」)・平均単価(別名「平均」)を取り出すSQLを書け。 コーディング★★☆無料
期待される結果

1行。2 / 173000 / 86500.0

ヒント

WHERE で絞ってから3つの集計関数を並べる。

模範解答
SELECT
  COUNT(*) AS 件数,
  SUM(price) AS 合計,
  AVG(price) AS 平均
FROM products
WHERE category = 'PC';
解説

カテゴリを変えれば別の集計が取れるが、毎回WHEREを書き換えるのは非効率。次章の GROUP BY を使えば、全カテゴリを1回で集計できる

SQL06-S04 【NULLの扱いで平均が変わる】price の平均を2通りで計算し、比較するSQLを書け。
① NULLを除いた平均(別名「除外平均」)② NULLを0として扱った平均(別名「ゼロ埋め平均」、小数第1位まで)
コーディング★★★無料
期待される結果

1行。35200.0 / 30171.4

ヒント

①は AVG(price)、②は AVG(COALESCE(price, 0))。②は ROUND で桁を揃える。

模範解答
SELECT
  AVG(price) AS 除外平均,
  ROUND(AVG(COALESCE(price, 0)), 1) AS ゼロ埋め平均
FROM products;
解説

同じデータから2つの異なる平均が出る。差は約5000円——分母が6か7かの違いだけでこれだけ変わる。どちらを報告するかは業務の定義で決めるべきで、SQLが自動で決めてくれるわけではない

SQL06-S05 【在庫評価額】在庫金額(price × stock)について、総額(別名「総額」)と、在庫金額が計算できた商品の件数(別名「対象件数」)を取り出すSQLを書け。 コーディング★★★無料
期待される結果

1行。総額 1422400 / 対象件数 5

ヒント

SUM(price * stock) と COUNT(price * stock) を並べる。NULLを含む計算結果はNULLになるので、COUNT から除かれる。

模範解答
SELECT
  SUM(price * stock) AS 総額,
  COUNT(price * stock) AS 対象件数
FROM products;
解説

7件中5件しか計算できていないことが分かる。新商品Aとサンプル品はNULLを含むため計算結果もNULLになり、集計から除かれた。総額だけ見ていては、この欠損に気づけない

5仕上げ課題

SQL06-FINAL 【商品マスタ サマリーレポート】経営会議用に、商品マスタ全体の状況を1行にまとめたサマリーを作れ。

表示する列
① 全商品数(別名「商品数」)
② カテゴリの種類数(別名「分類数」)
③ 価格が入力済みの件数(別名「価格登録済」)
④ 最安値(別名「最安値」)
⑤ 最高値(別名「最高値」)
⑥ 平均単価(NULLを除く、小数第1位まで)→ 別名「平均単価」
⑦ 在庫総額(price × stock の合計)→ 別名「在庫総額」

期待される結果(7列 × 1行)
商品数 | 分類数 | 価格登録済 | 最安値 | 最高値 | 平均単価 | 在庫総額
7 | 2 | 6 | 1500 | 128000 | 35200.0 | 1422400
期待される結果

7列 × 1行が完全一致

ヒント

COUNT(*)、COUNT(DISTINCT category)、COUNT(price)、MIN、MAX、ROUND(AVG(price),1)、SUM(price*stock) の7つを並べる。WHERE は不要。

模範解答
SELECT
  COUNT(*) AS 商品数,
  COUNT(DISTINCT category) AS 分類数,
  COUNT(price) AS 価格登録済,
  MIN(price) AS 最安値,
  MAX(price) AS 最高値,
  ROUND(AVG(price), 1) AS 平均単価,
  SUM(price * stock) AS 在庫総額
FROM products;
解説

7行のテーブルが、7つの数字に凝縮された。これが1万件でも100万件でも、返ってくるのは同じ1行だ。集計関数の威力はデータが大きくなるほど効いてくる。

このレポートには意図的に「商品数7」と「価格登録済6」を並べている。この2つの差が1あることで、読む人は「1件だけ価格が未入力だ」と気づける。集計値を1つだけ出すのではなく、比較できる形で並べる——これがレポート設計のコツだ。

そして平均単価35200円は6件で割った値である点に注意してほしい。もし「未入力は0円」という業務ルールなら、正しい平均は30171円になる。同じデータ、同じSQL、それでも答えが2つある。どちらが正しいかは、データベースではなく業務が決める。SQLを書く前に定義を確認する——これが数字を扱う仕事の基本になる。

次章では GROUP BY を学ぶ。今回は全体で1行だったが、「カテゴリごとに1行」という集計ができるようになり、レポートが一気に実用的になる。