データベースを扱っていると、「今月の売上合計はいくら?」「各店舗の売上を比較したい」「商品カテゴリ別の販売数量を知りたい」といった場面がよくありますよね。
そんなときに活躍するのが、SQLの「SUM関数」です。SUM関数を使えば、数値の合計を簡単に計算できます。
でも、基本的な使い方だけでなく、条件を指定したり、グループ別に集計したりする方法も知っておくと、とても便利です。
この記事では、SUM関数の基本から応用まで、実際のビジネス場面でよく使われるパターンを、初心者の方でもわかるように丁寧に説明します。
SUM関数とは何か?基本的な仕組み

SUM関数の役割
SUM関数は、指定したカラム(列)の数値をすべて足し算してくれるSQL関数です。
まるで電卓の「合計」ボタンのような機能ですね。
基本的な構文
SELECT SUM(カラム名) FROM テーブル名;
サンプルデータで理解しよう
以下のような売上データ(ordersテーブル)があるとします:
ordersテーブル
id | product_name | price | quantity | customer_id | order_date |
---|---|---|---|---|---|
1 | ノートPC | 80000 | 1 | 101 | 2025-06-01 |
2 | マウス | 2000 | 2 | 102 | 2025-06-01 |
3 | キーボード | 5000 | 1 | 103 | 2025-06-02 |
4 | モニター | 30000 | 1 | 101 | 2025-06-02 |
5 | USB ケーブル | 1000 | 3 | 104 | 2025-06-03 |
基本的なSUM関数の使用例
全商品の価格合計
SELECT SUM(price) FROM orders;
実行結果
SUM(price)
----------
118000
計算過程:80000 + 2000 + 5000 + 30000 + 1000 = 118000
全商品の販売数量合計
SELECT SUM(quantity) FROM orders;
実行結果
SUM(quantity)
-------------
8
計算過程:1 + 2 + 1 + 1 + 3 = 8
わかりやすい列名をつける
AS を使って結果に名前をつける
SELECT SUM(price) AS 売上合計 FROM orders;
実行結果
売上合計
--------
118000
複数の合計を同時に表示
SELECT
SUM(price) AS 売上合計,
SUM(quantity) AS 販売数量合計
FROM orders;
実行結果
売上合計 | 販売数量合計
---------|------------
118000 | 8
SUM関数が便利な場面
ビジネスでよく使われる例
- 売上分析:日別、月別、年別の売上合計
- 在庫管理:商品の総在庫数
- 予算管理:部署別の予算合計
- 顧客分析:顧客ごとの購入金額合計
- 成績管理:学生の点数合計
SUM関数の基本がわかったところで、次は条件を指定して、必要なデータだけの合計を求める方法を学びましょう。
WHERE句で条件付き合計を求める
条件を指定した合計の重要性
実際の業務では、「すべてのデータの合計」よりも「特定の条件に合うデータの合計」を求めることの方が多いです。
WHERE句を使えば、必要なデータだけを絞り込んで合計できます。
基本的な条件付き合計
特定の日の売上合計
SELECT SUM(price) AS 今日の売上
FROM orders
WHERE order_date = '2025-06-01';
実行結果
今日の売上
----------
82000
(ノートPC 80000円 + マウス 2000円 = 82000円)
一定金額以上の商品の合計
SELECT SUM(price) AS 高額商品合計
FROM orders
WHERE price >= 10000;
実行結果
高額商品合計
------------
110000
(ノートPC 80000円 + モニター 30000円 = 110000円)
日付範囲での集計
特定期間の売上合計
SELECT SUM(price) AS 期間売上
FROM orders
WHERE order_date BETWEEN '2025-06-01' AND '2025-06-02';
今月の売上合計
SELECT SUM(price) AS 今月売上
FROM orders
WHERE order_date >= '2025-06-01' AND order_date < '2025-07-01';
今年の売上合計
SELECT SUM(price) AS 今年売上
FROM orders
WHERE YEAR(order_date) = 2025;
文字列条件での集計
特定商品の売上合計
SELECT SUM(price) AS PC関連売上
FROM orders
WHERE product_name LIKE '%PC%';
特定文字が含まれない商品の合計
SELECT SUM(price) AS PC以外売上
FROM orders
WHERE product_name NOT LIKE '%PC%';
複数条件を組み合わせた集計
AND条件:すべての条件を満たす
-- 6月2日の高額商品(10000円以上)の合計
SELECT SUM(price) AS 高額商品売上
FROM orders
WHERE order_date = '2025-06-02' AND price >= 10000;
OR条件:いずれかの条件を満たす
-- PCまたはモニターの売上合計
SELECT SUM(price) AS PC関連売上
FROM orders
WHERE product_name LIKE '%PC%' OR product_name LIKE '%モニター%';
数量と価格を使った売上計算
実際の売上金額(単価×数量)
SELECT SUM(price * quantity) AS 実売上合計
FROM orders;
実行結果
実売上合計
----------
121000
計算過程
- ノートPC: 80000 × 1 = 80000
- マウス: 2000 × 2 = 4000
- キーボード: 5000 × 1 = 5000
- モニター: 30000 × 1 = 30000
- USBケーブル: 1000 × 3 = 3000
- 合計: 122000円
顧客別の購入合計
特定顧客の購入合計
SELECT SUM(price * quantity) AS 顧客購入合計
FROM orders
WHERE customer_id = 101;
購入金額が高い顧客のデータ
SELECT SUM(price * quantity) AS 高額顧客合計
FROM orders
WHERE customer_id IN (101, 102, 103);
実用的な条件付き集計例
今日の売上と昨日の売上を比較
-- 今日の売上
SELECT SUM(price * quantity) AS 今日売上
FROM orders
WHERE DATE(order_date) = CURDATE();
-- 昨日の売上
SELECT SUM(price * quantity) AS 昨日売上
FROM orders
WHERE DATE(order_date) = DATE_SUB(CURDATE(), INTERVAL 1 DAY);
営業時間内の売上
SELECT SUM(price * quantity) AS 営業時間売上
FROM orders
WHERE TIME(order_date) BETWEEN '09:00:00' AND '18:00:00';
季節商品の売上分析
-- 冬物商品の売上
SELECT SUM(price * quantity) AS 冬物売上
FROM orders
WHERE product_name LIKE '%コート%'
OR product_name LIKE '%マフラー%'
OR product_name LIKE '%手袋%';
WHERE句を使った条件指定により、必要なデータだけを効率的に集計できます。次は、カテゴリや部署別など、グループごとの合計を求める方法を学びましょう。
GROUP BYでカテゴリ別合計を求める

GROUP BYの基本概念
GROUP BYを使うと、データを特定の基準でグループ分けして、それぞれのグループごとに合計を計算できます。これは、カテゴリ別の売上分析や部署別の実績集計などで、非常によく使われる機能です。
サンプルデータの拡張
より実用的な例にするため、商品カテゴリを追加したテーブルを考えてみましょう:
orders_detailテーブル
id | product_name | category | price | quantity | order_date |
---|---|---|---|---|---|
1 | ノートPC | PC | 80000 | 1 | 2025-06-01 |
2 | マウス | PC | 2000 | 2 | 2025-06-01 |
3 | キーボード | PC | 5000 | 1 | 2025-06-02 |
4 | デスク | 家具 | 30000 | 1 | 2025-06-02 |
5 | 椅子 | 家具 | 15000 | 2 | 2025-06-03 |
6 | 本棚 | 家具 | 25000 | 1 | 2025-06-03 |
基本的なGROUP BY使用例
カテゴリ別の売上合計
SELECT
category AS カテゴリ,
SUM(price * quantity) AS 売上合計
FROM orders_detail
GROUP BY category;
実行結果
カテゴリ | 売上合計
---------|----------
PC | 89000
家具 | 95000
計算過程
- PCカテゴリ: (80000×1) + (2000×2) + (5000×1) = 89000
- 家具カテゴリ: (30000×1) + (15000×2) + (25000×1) = 95000
複数の集計値を同時に表示
カテゴリ別の詳細分析
SELECT
category AS カテゴリ,
COUNT(*) AS 商品数,
SUM(quantity) AS 販売数量,
SUM(price * quantity) AS 売上合計,
AVG(price) AS 平均単価
FROM orders_detail
GROUP BY category;
実行結果
カテゴリ | 商品数 | 販売数量 | 売上合計 | 平均単価
---------|--------|----------|----------|----------
PC | 3 | 4 | 89000 | 29000.00
家具 | 3 | 4 | 95000 | 23333.33
日付でグループ化
日別売上合計
SELECT
order_date AS 注文日,
SUM(price * quantity) AS 日別売上
FROM orders_detail
GROUP BY order_date
ORDER BY order_date;
実行結果
注文日 | 日別売上
-----------|----------
2025-06-01 | 84000
2025-06-02 | 35000
2025-06-03 | 65000
月別売上集計
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS 年月,
SUM(price * quantity) AS 月間売上
FROM orders_detail
GROUP BY DATE_FORMAT(order_date, '%Y-%m');
複数の列でグループ化
カテゴリ別・日別の売上分析
SELECT
category AS カテゴリ,
order_date AS 注文日,
SUM(price * quantity) AS 売上合計
FROM orders_detail
GROUP BY category, order_date
ORDER BY category, order_date;
実行結果
カテゴリ | 注文日 | 売上合計
---------|------------|----------
PC | 2025-06-01 | 84000
PC | 2025-06-02 | 5000
家具 | 2025-06-02 | 30000
家具 | 2025-06-03 | 65000
HAVING句で集計結果を絞り込み
GROUP BYで集計した結果に対して条件を指定するには、WHERE句ではなくHAVING句を使います。
売上が50000円以上のカテゴリのみ表示
SELECT
category AS カテゴリ,
SUM(price * quantity) AS 売上合計
FROM orders_detail
GROUP BY category
HAVING SUM(price * quantity) >= 50000;
実行結果
カテゴリ | 売上合計
---------|----------
PC | 89000
家具 | 95000
商品数が2個以上のカテゴリ
SELECT
category AS カテゴリ,
COUNT(*) AS 商品数,
SUM(price * quantity) AS 売上合計
FROM orders_detail
GROUP BY category
HAVING COUNT(*) >= 2;
実用的なGROUP BY活用例
店舗別売上ランキング
SELECT
store_name AS 店舗名,
SUM(price * quantity) AS 売上合計
FROM orders_detail
GROUP BY store_name
ORDER BY SUM(price * quantity) DESC;
営業担当者別実績
SELECT
sales_person AS 営業担当,
COUNT(*) AS 受注件数,
SUM(price * quantity) AS 売上合計,
AVG(price * quantity) AS 平均受注額
FROM orders_detail
GROUP BY sales_person
ORDER BY 売上合計 DESC;
時間帯別売上分析
SELECT
HOUR(order_datetime) AS 時間帯,
COUNT(*) AS 注文件数,
SUM(price * quantity) AS 売上合計
FROM orders_detail
GROUP BY HOUR(order_datetime)
ORDER BY 時間帯;
四半期別売上推移
SELECT
YEAR(order_date) AS 年,
QUARTER(order_date) AS 四半期,
SUM(price * quantity) AS 売上合計
FROM orders_detail
GROUP BY YEAR(order_date), QUARTER(order_date)
ORDER BY 年, 四半期;
WHERE句とGROUP BYの組み合わせ
今年のカテゴリ別売上
SELECT
category AS カテゴリ,
SUM(price * quantity) AS 今年売上
FROM orders_detail
WHERE YEAR(order_date) = 2025
GROUP BY category;
高額商品(10000円以上)のカテゴリ別分析
SELECT
category AS カテゴリ,
COUNT(*) AS 高額商品数,
SUM(price * quantity) AS 高額商品売上
FROM orders_detail
WHERE price >= 10000
GROUP BY category;
GROUP BYを使いこなせるようになると、データの傾向や特徴を把握するのがとても楽になります。次は、NULL値がある場合の注意点を学びましょう。
NULL値の扱い方と注意点

NULL値とSUM関数の関係
SUM関数を使うときに注意が必要なのが、NULL値の扱いです。NULL値があるカラムを集計する場合、思わぬ結果になることがあります。
NULL値の基本的な動作
NULLを含むサンプルデータ
id | product_name | price | quantity | discount |
---|---|---|---|---|
1 | ノートPC | 80000 | 1 | 5000 |
2 | マウス | 2000 | 2 | NULL |
3 | キーボード | 5000 | 1 | 500 |
4 | モニター | NULL | 1 | 1000 |
5 | USBケーブル | 1000 | 3 | NULL |
基本的なSUM関数の動作
-- 価格の合計(NULLは無視される)
SELECT SUM(price) AS 価格合計 FROM products;
実行結果
価格合計
--------
88000
(80000 + 2000 + 5000 + 1000 = 88000、NULLのモニターは除外)
割引額の合計
SELECT SUM(discount) AS 割引合計 FROM products;
実行結果
割引合計
--------
6500
(5000 + 500 + 1000 = 6500、NULLは除外)
NULL値の問題点
1. 件数とSUMの不一致
SELECT
COUNT(*) AS 全件数,
COUNT(price) AS 価格件数,
SUM(price) AS 価格合計
FROM products;
実行結果
全件数 | 価格件数 | 価格合計
-------|----------|----------
5 | 4 | 88000
全部で5件あるのに、価格が設定されているのは4件だけです。
2. 平均値の計算への影響
-- NULLを無視した平均
SELECT AVG(discount) AS 割引平均 FROM products;
-- 結果: 2166.67 (6500 ÷ 3件)
-- 全件を対象とした場合の期待値
-- 6500 ÷ 5件 = 1300 とは異なる
NULL値を0として扱う方法
COALESCE関数を使用
-- NULLを0に置き換えて合計
SELECT SUM(COALESCE(discount, 0)) AS 割引合計 FROM products;
実行結果
割引合計
--------
6500
IFNULL関数を使用(MySQL)
SELECT SUM(IFNULL(discount, 0)) AS 割引合計 FROM products;
ISNULL関数を使用(SQL Server)
SELECT SUM(ISNULL(discount, 0)) AS 割引合計 FROM products;
NULL値を考慮した実用的な計算
実際の支払金額を計算
SELECT
product_name,
price,
COALESCE(discount, 0) AS 割引額,
(price - COALESCE(discount, 0)) AS 実支払額
FROM products
WHERE price IS NOT NULL;
実行結果
product_name | price | 割引額 | 実支払額
-------------|-------|--------|----------
ノートPC | 80000 | 5000 | 75000
マウス | 2000 | 0 | 2000
キーボード | 5000 | 500 | 4500
USBケーブル | 1000 | 0 | 1000
カテゴリ別の割引率分析
SELECT
category,
COUNT(*) AS 商品数,
COUNT(discount) AS 割引設定数,
SUM(COALESCE(discount, 0)) AS 割引合計,
AVG(COALESCE(discount, 0)) AS 平均割引額
FROM products
GROUP BY category;
NULL値チェックの重要性
NULL値の件数を確認
SELECT
COUNT(*) AS 全件数,
COUNT(price) AS 価格設定済み,
COUNT(*) - COUNT(price) AS 価格未設定,
COUNT(discount) AS 割引設定済み,
COUNT(*) - COUNT(discount) AS 割引未設定
FROM products;
NULL値がある行を特定
-- 価格が未設定の商品
SELECT * FROM products WHERE price IS NULL;
-- 割引が未設定の商品
SELECT * FROM products WHERE discount IS NULL;
-- 価格または割引が未設定の商品
SELECT * FROM products WHERE price IS NULL OR discount IS NULL;
実務での対処法
1. データ入力時の制約
-- テーブル作成時にNOT NULL制約を設定
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL, -- NULL不可
discount DECIMAL(10,2) DEFAULT 0 -- デフォルト値0
);
2. 集計前のデータクリーニング
-- 価格が設定されている商品のみで集計
SELECT
category,
SUM(price) AS カテゴリ別売上
FROM products
WHERE price IS NOT NULL
GROUP BY category;
3. NULL値を明示的に処理
-- 売上から割引を引いた実売上
SELECT
SUM(price * quantity - COALESCE(discount * quantity, 0)) AS 実売上
FROM orders;
よくある間違いと対処法
間違い:NULL値を考慮しない集計
-- 問題のあるクエリ
SELECT
AVG(price) AS 平均価格,
SUM(price) / COUNT(*) AS 平均価格2
FROM products;
-- 結果が異なる場合がある
正しい:NULL値を明示的に処理
-- 正しいクエリ
SELECT
AVG(COALESCE(price, 0)) AS 平均価格,
SUM(COALESCE(price, 0)) / COUNT(*) AS 平均価格2
FROM products;
-- 同じ結果になる
NULL値の扱いを理解することで、正確な集計結果を得ることができます。次は、SUM関数と他の集計関数を組み合わせた応用的な使い方を学びましょう。
SUM関数と他の集計関数の組み合わせ

集計関数の種類と役割
SUM関数は他の集計関数と組み合わせることで、より詳細で有用な分析ができます。主要な集計関数を覚えておきましょう。
主要な集計関数
関数 | 役割 | 例 |
---|---|---|
SUM() | 合計値 | SUM(price) |
COUNT() | 行数・件数 | COUNT(*) |
AVG() | 平均値 | AVG(price) |
MAX() | 最大値 | MAX(price) |
MIN() | 最小値 | MIN(price) |
基本的な組み合わせ例
売上の基本統計情報
SELECT
COUNT(*) AS 注文件数,
SUM(price * quantity) AS 売上合計,
AVG(price * quantity) AS 平均注文額,
MAX(price * quantity) AS 最高注文額,
MIN(price * quantity) AS 最低注文額
FROM orders;
実行結果
注文件数 | 売上合計 | 平均注文額 | 最高注文額 | 最低注文額
---------|----------|------------|------------|------------
5 | 122000 | 24400.00 | 80000 | 3000
カテゴリ別の詳細分析
商品カテゴリ別の包括的分析
SELECT
category AS カテゴリ,
COUNT(*) AS 商品数,
SUM(price) AS 価格合計,
AVG(price) AS 平均価格,
MAX(price) AS 最高価格,
MIN(price) AS 最低価格,
SUM(quantity) AS 販売数量合計,
SUM(price * quantity) AS 売上合計
FROM orders
GROUP BY category
ORDER BY 売上合計 DESC;
実行結果
カテゴリ | 商品数 | 価格合計 | 平均価格 | 最高価格 | 最低価格 | 販売数量合計 | 売上合計
---------|--------|----------|-----------|----------|----------|--------------|----------
PC | 3 | 87000 | 29000.00 | 80000 | 2000 | 4 | 89000
家具 | 2 | 45000 | 22500.00 | 30000 | 15000 | 3 | 75000
時系列分析
月別売上トレンド
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS 年月,
COUNT(*) AS 注文件数,
SUM(price * quantity) AS 月間売上,
AVG(price * quantity) AS 月間平均注文額,
COUNT(DISTINCT customer_id) AS 購入顧客数
FROM orders
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY 年月;
週別売上比較
SELECT
WEEK(order_date) AS 週番号,
DAYOFWEEK(order_date) AS 曜日,
COUNT(*) AS 注文件数,
SUM(price * quantity) AS 日別売上,
AVG(price * quantity) AS 平均注文額
FROM orders
GROUP BY WEEK(order_date), DAYOFWEEK(order_date)
ORDER BY 週番号, 曜日;
顧客分析
顧客別購入統計
SELECT
customer_id AS 顧客ID,
COUNT(*) AS 注文回数,
SUM(price * quantity) AS 累計購入額,
AVG(price * quantity) AS 平均注文額,
MAX(price * quantity) AS 最高注文額,
MIN(order_date) AS 初回注文日,
MAX(order_date) AS 最終注文日
FROM orders
GROUP BY customer_id
ORDER BY 累計購入額 DESC;
顧客ランク別分析
SELECT
CASE
WHEN 累計購入額 >= 100000 THEN 'VIP'
WHEN 累計購入額 >= 50000 THEN 'ゴールド'
WHEN 累計購入額 >= 20000 THEN 'シルバー'
ELSE 'ブロンズ'
END AS 顧客ランク,
COUNT(*) AS 顧客数,
AVG(累計購入額) AS 平均購入額,
SUM(累計購入額) AS ランク別売上合計
FROM (
SELECT
customer_id,
SUM(price * quantity) AS 累計購入額
FROM orders
GROUP BY customer_id
) AS customer_summary
GROUP BY
CASE
WHEN 累計購入額 >= 100000 THEN 'VIP'
WHEN 累計購入額 >= 50000 THEN 'ゴールド'
WHEN 累計購入額 >= 20000 THEN 'シルバー'
ELSE 'ブロンズ'
END
ORDER BY 平均購入額 DESC;
商品分析
商品別売上ランキング
SELECT
product_name AS 商品名,
COUNT(*) AS 注文回数,
SUM(quantity) AS 総販売数量,
SUM(price * quantity) AS 売上合計,
AVG(quantity) AS 平均注文数量,
MAX(quantity) AS 最大注文数量
FROM orders
GROUP BY product_name
ORDER BY 売上合計 DESC
LIMIT 10;
価格帯別売上分析
SELECT
CASE
WHEN price < 5000 THEN '5000円未満'
WHEN price < 20000 THEN '5000円以上20000円未満'
WHEN price < 50000 THEN '20000円以上50000円未満'
ELSE '50000円以上'
END AS 価格帯,
COUNT(*) AS 商品数,
SUM(quantity) AS 販売数量,
SUM(price * quantity) AS 売上合計,
AVG(price) AS 平均価格
FROM orders
GROUP BY
CASE
WHEN price < 5000 THEN '5000円未満'
WHEN price < 20000 THEN '5000円以上20000円未満'
WHEN price < 50000 THEN '20000円以上50000円未満'
ELSE '50000円以上'
END
ORDER BY 売上合計 DESC;
複雑な比率計算
カテゴリ別売上シェア
SELECT
category AS カテゴリ,
SUM(price * quantity) AS カテゴリ売上,
(SUM(price * quantity) * 100.0 / (SELECT SUM(price * quantity) FROM orders)) AS 売上シェア率
FROM orders
GROUP BY category
ORDER BY カテゴリ売上 DESC;
実行結果
カテゴリ | カテゴリ売上 | 売上シェア率
---------|--------------|-------------
PC | 89000 | 72.95
家具 | 33000 | 27.05
前年同期比較
月別前年同期比
SELECT
DATE_FORMAT(order_date, '%m') AS 月,
SUM(CASE WHEN YEAR(order_date) = 2025 THEN price * quantity ELSE 0 END) AS 今年売上,
SUM(CASE WHEN YEAR(order_date) = 2024 THEN price * quantity ELSE 0 END) AS 前年売上,
(SUM(CASE WHEN YEAR(order_date) = 2025 THEN price * quantity ELSE 0 END) -
SUM(CASE WHEN YEAR(order_date) = 2024 THEN price * quantity ELSE 0 END)) AS 売上差額,
ROUND(
(SUM(CASE WHEN YEAR(order_date) = 2025 THEN price * quantity ELSE 0 END) -
SUM(CASE WHEN YEAR(order_date) = 2024 THEN price * quantity ELSE 0 END)) * 100.0 /
NULLIF(SUM(CASE WHEN YEAR(order_date) = 2024 THEN price * quantity ELSE 0 END), 0),
2
) AS 成長率
FROM orders
WHERE YEAR(order_date) IN (2024, 2025)
GROUP BY DATE_FORMAT(order_date, '%m')
ORDER BY 月;
パフォーマンス指標
営業効率分析
SELECT
sales_person AS 営業担当,
COUNT(*) AS 商談件数,
COUNT(CASE WHEN status = 'completed' THEN 1 END) AS 成約件数,
(COUNT(CASE WHEN status = 'completed' THEN 1 END) * 100.0 / COUNT(*)) AS 成約率,
SUM(CASE WHEN status = 'completed' THEN price * quantity ELSE 0 END) AS 売上合計,
AVG(CASE WHEN status = 'completed' THEN price * quantity END) AS 平均成約額
FROM orders
GROUP BY sales_person
ORDER BY 売上合計 DESC;
在庫分析
商品回転率分析
SELECT
p.product_name AS 商品名,
p.stock AS 現在庫数,
COALESCE(SUM(o.quantity), 0) AS 月間販売数,
CASE
WHEN p.stock > 0 THEN ROUND(COALESCE(SUM(o.quantity), 0) / p.stock, 2)
ELSE NULL
END AS 在庫回転率,
COALESCE(SUM(o.price * o.quantity), 0) AS 月間売上
FROM products p
LEFT JOIN orders o ON p.product_name = o.product_name
AND o.order_date >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
GROUP BY p.product_name, p.stock
ORDER BY 在庫回転率 DESC;
実用的なダッシュボード用クエリ
経営ダッシュボード用の総合指標
SELECT
'売上' AS 項目,
SUM(price * quantity) AS 今日,
(SELECT SUM(price * quantity) FROM orders WHERE DATE(order_date) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)) AS 昨日,
(SELECT SUM(price * quantity) FROM orders WHERE MONTH(order_date) = MONTH(CURDATE()) AND YEAR(order_date) = YEAR(CURDATE())) AS 今月
FROM orders
WHERE DATE(order_date) = CURDATE()
UNION ALL
SELECT
'注文件数' AS 項目,
COUNT(*) AS 今日,
(SELECT COUNT(*) FROM orders WHERE DATE(order_date) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)) AS 昨日,
(SELECT COUNT(*) FROM orders WHERE MONTH(order_date) = MONTH(CURDATE()) AND YEAR(order_date) = YEAR(CURDATE())) AS 今月
FROM orders
WHERE DATE(order_date) = CURDATE()
UNION ALL
SELECT
'平均注文額' AS 項目,
AVG(price * quantity) AS 今日,
(SELECT AVG(price * quantity) FROM orders WHERE DATE(order_date) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)) AS 昨日,
(SELECT AVG(price * quantity) FROM orders WHERE MONTH(order_date) = MONTH(CURDATE()) AND YEAR(order_date) = YEAR(CURDATE())) AS 今月
FROM orders
WHERE DATE(order_date) = CURDATE();
実用的なSUM関数活用パターン

ビジネス場面別の活用例
実際のビジネスでSUM関数がどのように使われているか、具体的なパターンを紹介します。
ECサイトの売上分析
日別売上と目標達成率
SELECT
DATE(order_date) AS 日付,
COUNT(*) AS 注文件数,
SUM(price * quantity) AS 日別売上,
100000 AS 日別目標,
ROUND((SUM(price * quantity) / 100000) * 100, 1) AS 目標達成率
FROM orders
WHERE order_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY DATE(order_date)
ORDER BY 日付 DESC;
送料を含む実売上計算
SELECT
DATE(order_date) AS 日付,
SUM(price * quantity) AS 商品売上,
SUM(shipping_fee) AS 送料合計,
SUM(price * quantity + shipping_fee) AS 実売上,
SUM(CASE WHEN shipping_fee = 0 THEN 1 ELSE 0 END) AS 送料無料件数
FROM orders
GROUP BY DATE(order_date)
ORDER BY 日付 DESC;
小売店の在庫管理
商品別の収益性分析
SELECT
product_name AS 商品名,
SUM(quantity) AS 販売数量,
AVG(cost_price) AS 平均仕入価格,
AVG(selling_price) AS 平均販売価格,
SUM((selling_price - cost_price) * quantity) AS 粗利合計,
ROUND(AVG((selling_price - cost_price) / selling_price * 100), 1) AS 粗利率
FROM sales
GROUP BY product_name
HAVING SUM(quantity) > 0
ORDER BY 粗利合計 DESC;
カテゴリ別の在庫回転状況
SELECT
category AS カテゴリ,
SUM(current_stock) AS 現在庫総数,
SUM(sales_quantity) AS 月間販売数,
ROUND(SUM(sales_quantity) / NULLIF(SUM(current_stock), 0), 2) AS 在庫回転率,
SUM(dead_stock_value) AS デッドストック金額
FROM inventory_summary
GROUP BY category
ORDER BY 在庫回転率 DESC;
製造業の生産管理
生産ライン別効率分析
SELECT
production_line AS 生産ライン,
SUM(production_quantity) AS 生産数量,
SUM(defect_quantity) AS 不良品数,
ROUND((1 - SUM(defect_quantity) / NULLIF(SUM(production_quantity), 0)) * 100, 2) AS 良品率,
SUM(production_cost) AS 生産コスト,
ROUND(SUM(production_cost) / NULLIF(SUM(production_quantity), 0), 2) AS 単位コスト
FROM production_data
WHERE production_date >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
GROUP BY production_line
ORDER BY 良品率 DESC;
飲食店の売上管理
時間帯別売上分析
SELECT
CASE
WHEN HOUR(order_time) BETWEEN 6 AND 10 THEN '朝食'
WHEN HOUR(order_time) BETWEEN 11 AND 14 THEN 'ランチ'
WHEN HOUR(order_time) BETWEEN 15 AND 17 THEN 'おやつ'
WHEN HOUR(order_time) BETWEEN 18 AND 22 THEN 'ディナー'
ELSE 'その他'
END AS 時間帯,
COUNT(*) AS 注文件数,
SUM(order_amount) AS 売上合計,
AVG(order_amount) AS 平均客単価,
SUM(customer_count) AS 来客数
FROM restaurant_orders
WHERE order_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
GROUP BY
CASE
WHEN HOUR(order_time) BETWEEN 6 AND 10 THEN '朝食'
WHEN HOUR(order_time) BETWEEN 11 AND 14 THEN 'ランチ'
WHEN HOUR(order_time) BETWEEN 15 AND 17 THEN 'おやつ'
WHEN HOUR(order_time) BETWEEN 18 AND 22 THEN 'ディナー'
ELSE 'その他'
END
ORDER BY 売上合計 DESC;
不動産業の契約管理
営業担当者別成績
SELECT
sales_person AS 営業担当,
COUNT(*) AS 契約件数,
SUM(contract_amount) AS 契約金額合計,
AVG(contract_amount) AS 平均契約額,
SUM(commission) AS 手数料合計,
ROUND(AVG(DATEDIFF(contract_date, first_contact_date)), 1) AS 平均成約日数
FROM real_estate_contracts
WHERE contract_date >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH)
GROUP BY sales_person
ORDER BY 契約金額合計 DESC;
教育機関の成績管理
科目別成績統計
SELECT
subject AS 科目,
COUNT(*) AS 受験者数,
SUM(score) AS 得点合計,
AVG(score) AS 平均点,
MAX(score) AS 最高点,
MIN(score) AS 最低点,
SUM(CASE WHEN score >= 80 THEN 1 ELSE 0 END) AS 優秀者数,
ROUND(SUM(CASE WHEN score >= 60 THEN 1 ELSE 0 END) / COUNT(*) * 100, 1) AS 合格率
FROM exam_results
WHERE exam_date >= '2025-04-01'
GROUP BY subject
ORDER BY 平均点 DESC;
医療機関の収益分析
診療科別売上分析
SELECT
department AS 診療科,
COUNT(*) AS 患者数,
SUM(medical_fee) AS 診療報酬合計,
AVG(medical_fee) AS 平均診療費,
SUM(insurance_amount) AS 保険請求額,
SUM(patient_payment) AS 患者負担額,
ROUND(AVG(treatment_time), 1) AS 平均診療時間
FROM medical_records
WHERE visit_date >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
GROUP BY department
ORDER BY 診療報酬合計 DESC;
パフォーマンス最適化のコツ
効率的なSUM関数の使用
-- 推奨:必要なカラムのみをSELECT
SELECT
category,
SUM(price * quantity) AS 売上
FROM orders
WHERE order_date >= '2025-06-01'
GROUP BY category;
-- 非推奨:不要なカラムも取得
SELECT
*,
SUM(price * quantity) AS 売上
FROM orders
WHERE order_date >= '2025-06-01'
GROUP BY category;
インデックスを活用した高速化
-- WHERE句やGROUP BYで使用するカラムにインデックス作成
CREATE INDEX idx_order_date_category ON orders(order_date, category);
-- 効率的な集計クエリ
SELECT
category,
DATE(order_date) AS 日付,
SUM(price * quantity) AS 日別売上
FROM orders
WHERE order_date >= '2025-06-01'
GROUP BY category, DATE(order_date)
ORDER BY category, 日付;
まとめ
SQLのSUM関数は、データ分析と業務改善において欠かせない重要なツールです。この記事で学んだ内容を整理してみましょう。
SUM関数の基本ポイント
- SUM関数は指定したカラムの数値を合計する
- WHERE句で条件を指定して、必要なデータだけを集計
- GROUP BYでカテゴリ別や期間別の集計が可能
- NULL値は自動的に除外される(必要に応じてCOALESCE等で対処)
実用的な活用パターン
- 売上分析:期間別、カテゴリ別、担当者別の売上集計
- 在庫管理:商品別の販売数量や在庫回転率の計算
- 顧客分析:購入額や購入回数による顧客セグメント
- パフォーマンス分析:目標達成率や効率指標の算出
他の集計関数との組み合わせ
-- 包括的な分析例
SELECT
category AS カテゴリ,
COUNT(*) AS 件数,
SUM(price * quantity) AS 売上合計,
AVG(price * quantity) AS 平均注文額,
MAX(price) AS 最高単価,
MIN(price) AS 最低単価
FROM orders
GROUP BY category;
コメント