SQL集計関数で件数や売上を確認する前に整理すること
Webサイトの売上レポートを作成する際、「今月の総売上はいくら?」「商品の平均単価は?」「一番高く売れた商品は何?」といった情報は不可欠です。データベースに蓄積された個々のデータを、意味のある一つの数値に集約して取り出したい――そんなときに絶大なパワーを発揮するのが、SQLの集計関数です。
集計関数とは、複数の行にまたがるデータを入力として受け取り、その集計結果として単一の値を返す関数のことです。例えるなら、たくさんの数字が書かれた紙を電卓に読み込ませて、「合計」や「平均」といった一つの答えを出力させるようなものです。
この記事では、SUM(), AVG(), MAX(), MIN() の使い方に加えて、本番DBで集計SQLを実行する前に何を確認するか、AIに集計SQLを相談する時に何を伏せるかを整理します。集計は読み取り中心の操作ですが、間違った条件で見た数字を信じると、売上、問い合わせ件数、管理画面の判断を誤るため、先に目的と対象範囲を分けます。
確認日: 2026年5月19日
このページで整理できること
SUM()、AVG()、MAX()、MIN()を使う場面。- 売上、問い合わせ件数、平均値、最大値を確認する前に決める条件。
WHERE、GROUP BY、HAVINGと集計関数の役割分担。- AIが出した集計SQLを本番DBで試す前に伏せる情報と確認順。
最初に分けること
| 知りたいこと | 使う関数や句 | 先に確認すること |
|---|---|---|
| 問い合わせや注文の件数 | COUNT() |
対象期間、ステータス、テストデータを含めるかを決める |
| 売上や数量の合計 | SUM() |
税込/税抜、キャンセル、重複注文をどう扱うかを決める |
| 平均単価や平均スコア | AVG() |
NULL や0円データが平均に入ってよいか確認する |
| カテゴリ別・日別に見る | GROUP BY |
グループ化する列と、集計後に絞る条件を分ける |
まず何を集計したいかを決める
SQLの集計で迷ったときは、関数名から選ぶよりも「知りたい答え」から逆算すると失敗しにくくなります。
- 件数を知りたい:
COUNT()でレコード数を数える - 合計・平均・最大・最小を知りたい: このページの
SUM()/AVG()/MAX()/MIN() - カテゴリ別・日別・ユーザー別に分けたい:
GROUP BYでグループ化する - 集計後の結果だけを絞りたい:
HAVINGで集計結果を絞る
まだ SELECT や WHERE が不安な場合は、先に SELECT文の基本 と WHERE句の基本 を確認してから進むと理解しやすいです。
準備:集計対象の売上データを用意しよう
集計関数を試すには、集計対象となる数値データが必要です。今回は、ECサイトの売上履歴を模した`sales`テーブルを作成します。複数のカテゴリや異なる価格・数量のデータを含めることで、各関数の働きがより明確に分かります。
-- もしsalesテーブルが存在すれば削除(繰り返し試せるように)
DROP TABLE IF EXISTS sales;
-- 新しいsalesテーブルを作成
CREATE TABLE sales (
id INTEGER PRIMARY KEY,
product_name TEXT NOT NULL,
category TEXT NOT NULL,
price INTEGER NOT NULL,
quantity INTEGER NOT NULL,
sale_date DATE NOT NULL
);
-- 初期データを挿入
INSERT INTO sales (id, product_name, category, price, quantity, sale_date) VALUES
(1, 'すごいボールペン', '文房具', 150, 10, '2025-07-01'),
(2, '魔法のノート', '文房具', 300, 5, '2025-07-01'),
(3, '究極の炊飯器', '家電', 25000, 2, '2025-07-02'),
(4, '奇跡のリンゴ', '食品', 500, 20, '2025-07-03'),
(5, 'USB-Cハブ', 'PC周辺機器', 4000, 3, '2025-07-03'),
(6, '伝統の筆', '文房具', 1200, 8, '2025-07-04'),
(7, '高級チョコレート', '食品', 3500, 5, '2025-07-05'),
(8, 'すごいボールペン', '文房具', 150, 15, '2025-07-05');
これで、様々な角度からデータを集計する準備が整いました。
【合計】`SUM()`関数で合計値を求める
SUM()関数は、指定した数値列の合計値を計算します。「売上合計」「総在庫数」「合計ポイント」など、ビジネスで「合計」を知りたい場面は非常に多く、最も基本的な集計関数の一つです。
SUM()の括弧の中には、合計したい列名を指定します。列同士の計算結果を合計することも可能です。
シナリオ:「すべての売上の総額(総売上高)はいくらか?」
この場合、各レコードの「価格(price) × 数量(quantity)」を計算し、その結果をすべて合計します。
SELECT SUM(price * quantity) AS total_revenue FROM sales;
実行結果:
total_revenue
-------------
102850
AS total_revenueを使って、結果の列に「総売上」を意味する分かりやすい名前を付けている点もポイントです。
【平均】`AVG()`関数で平均値を求める
AVG()(Averageの略)関数は、指定した数値列の平均値を計算します。「平均年齢」「平均スコア」「平均単価」など、データ全体の傾向を把握するのに役立ちます。
シナリオ:「販売された商品の平均単価はいくらか?」
SELECT AVG(price) AS average_price FROM sales;
実行結果:
average_price
-------------
5562.5
注意点として、SUM()やAVG()は、計算対象の列に`NULL`が含まれている場合、その行を無視して集計を行います。これは意図しない結果を招くことがあるため、覚えておきましょう。
【最大・最小】`MAX()` と `MIN()`関数で最大値・最小値を求める
MAX()(Maximum)とMIN()(Minimum)は、その名の通り、列内の最大値と最小値を取得するための関数です。この2つはセットで覚えるのが効率的です。
`MAX()`関数:最も大きい値を見つける
シナリオ:「一度の取引で最も高額だった売上はいくらか?」
SELECT MAX(price * quantity) AS highest_sale FROM sales;
実行結果:
highest_sale
------------
50000
これはID 3の「究極の炊飯器」(25,000 × 2)の売上ですね。
`MIN()`関数:最も小さい値を見つける
シナリオ:「販売された商品の中で、最も単価が安いものはいくらか?」
SELECT MIN(price) AS cheapest_price FROM sales;
実行結果:
cheapest_price
--------------
150
`MAX()`と`MIN()`は数値だけでなく、日付(最も新しい/古い日)や文字列(辞書順で最後/最初)にも使うことができ、非常に汎用性が高い関数です。
【最強の組み合わせ】`GROUP BY`句と集計関数
これら4つの集計関数の真価が最も発揮されるのが、GROUP BY句との組み合わせです。GROUP BYを使うと、特定の列の値でデータをグループ化し、そのグループ**ごと**に集計関数を適用できます。
「カテゴリごとの売上合計」や「商品ごとの平均販売数」といった、より実践的で詳細な分析が可能になります。
シナリオ:「商品カテゴリごとに、総売上、平均単価、販売総数を集計したい」
SELECT
category,
SUM(price * quantity) AS total_revenue,
AVG(price) AS average_price,
SUM(quantity) AS total_quantity_sold
FROM
sales
GROUP BY
category;
実行結果:
category | total_revenue | average_price | total_quantity_sold
----------|---------------|---------------|---------------------
PC周辺機器 | 12000 | 4000 | 3
家電 | 50000 | 25000 | 2
文房具 | 13350 | 550 | 33
食品 | 27500 | 2000 | 25
この一つのクエリで、カテゴリ別の詳細な販売実績が一目瞭然になりました。このように、集計関数と`GROUP BY`を組み合わせることで、単なる数字の羅列だった生データから、ビジネスに役立つ「インサイト」を引き出すことができるのです。
集計結果をさらに絞り込むならHAVING
WHERE は集計前の行を絞るために使い、HAVING は GROUP BY でまとめた後の結果を絞るために使います。たとえば「カテゴリ別に集計したうえで、売上が1万円以上のカテゴリだけ見たい」という場合は HAVING が必要です。
SELECT
category,
SUM(price * quantity) AS total_revenue
FROM
sales
GROUP BY
category
HAVING
SUM(price * quantity) >= 10000;
WHERE と HAVING の違いで混乱したら、GROUP BYとHAVINGの使い分けで確認できます。
本番DBで集計SQLを使う前に止まる場所
集計SQLは、UPDATE や DELETE のようにデータを直接変更しないため安全に見えます。しかし、集計条件を間違えると、売上、問い合わせ数、在庫、会員数などの判断を誤ります。本番DBで数字を見る前に、次を確認します。
- ローカル、テスト、本番のどのDBを見ているかを確認する。
- 対象期間、除外するテストデータ、キャンセルや下書きの扱いを決める。
WHEREで集計前の行を絞るのか、HAVINGで集計後の結果を絞るのかを分ける。- 集計前に
COUNT()やSELECTで対象行を確認する。 - AIへ相談する時は、実在する顧客名、メールアドレス、注文内容、DB接続情報を貼らない。
SQLを本番DBで試す前に不安がある場合は、AIが作ったSQLを実行前に確認するメモメーカー と ロリポップで自作PHPサイトを安全に更新する入口 へ戻って、作業範囲を整理してください。
AIにSQL集計について相談するメモ
AIやCodexへ相談する時は、実データを貼らず、テーブル構造と知りたい数字だけを渡します。
SQL集計について相談します。
知りたい数字:
- 件数 / 合計 / 平均 / 最大 / 最小 / グループ別集計:
対象:
- テーブル名:
- 集計したい列:
- 絞り込みたい条件:
- 期間:
確認したいこと:
- WHEREとHAVINGの使い分け
- GROUP BYに含める列
- NULLや0の扱い
- 実行前にCOUNTで確認するSQL
貼らない情報:
- DBホスト、ユーザー名、パスワード
- 実在する顧客名、メールアドレス、注文内容
- 本番の管理画面URL
【体験コーナー】ブラウザでSQLを動かし、データ集計を体験しよう!
さあ、知識をスキルに変える時間です! 以下のHTMLコードを丸ごとコピーして、sql_aggregate_test.htmlのようなファイル名で保存し、ブラウザで開いてみてください。あなた専用のSQL実行環境が立ち上がり、この記事で使っているsalesテーブルが用意されています。
`SUM`を`AVG`に変えてみたり、`GROUP BY`に追加する列を変えてみたりと、自由に試行錯誤して、データが集計され、意味のある情報に変わっていく様子をその目で確かめてみましょう!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL集計関数 オンライン実行環境</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.7; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
h1 { color: #2980b9; }
textarea { width: 100%; height: 220px; font-family: "SF Mono", "Consolas", monospace; font-size: 16px; padding: 12px; border: 1px solid #ccc; border-radius: 6px; box-sizing: border-box; margin-bottom: 1rem; }
button { background-color: #3498db; color: white; border: none; padding: 12px 22px; font-size: 16px; border-radius: 6px; cursor: pointer; transition: background-color 0.2s; }
button:hover { background-color: #2980b9; }
button:disabled { background-color: #bdc3c7; cursor: not-allowed; }
#result-container { margin-top: 2rem; border: 1px solid #ddd; padding: 1rem; border-radius: 6px; background: #fdfdfd; min-height: 50px; }
#error-message { color: #e74c3c; font-weight: bold; }
table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
th { background-color: #f2f2f2; }
tr:nth-child(even) { background-color: #f9f9f9; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
</head>
<body>
<h1>SQLを試してみよう!</h1>
<p>下のテキストエリアにSQL文を入力して「実行」ボタンを押してください。色々な集計を試してみましょう!</p>
<textarea id="sql-input">-- 商品名でグループ化して、各商品の総売上と販売総数を計算してみよう
SELECT
product_name,
SUM(price * quantity) AS total_revenue,
SUM(quantity) AS total_quantity
FROM
sales
GROUP BY
product_name
ORDER BY
total_revenue DESC;
</textarea>
<button id="execute-btn">実行</button>
<div id="result-container">
<p id="error-message"></p>
<div id="result-output"></div>
</div>
<script>
const sqlInput = document.getElementById('sql-input');
const executeBtn = document.getElementById('execute-btn');
const errorMsg = document.getElementById('error-message');
const resultOutput = document.getElementById('result-output');
let db;
async function initDb() {
executeBtn.disabled = true;
executeBtn.textContent = 'DB準備中...';
try {
const SQL = await initSqlJs({
locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${file}`
});
db = new SQL.Database();
const setupSql = `
DROP TABLE IF EXISTS sales;
CREATE TABLE sales (id INTEGER PRIMARY KEY, product_name TEXT NOT NULL, category TEXT NOT NULL, price INTEGER NOT NULL, quantity INTEGER NOT NULL, sale_date DATE NOT NULL);
INSERT INTO sales (id, product_name, category, price, quantity, sale_date) VALUES
(1, 'すごいボールペン', '文房具', 150, 10, '2025-07-01'),
(2, '魔法のノート', '文房具', 300, 5, '2025-07-01'),
(3, '究極の炊飯器', '家電', 25000, 2, '2025-07-02'),
(4, '奇跡のリンゴ', '食品', 500, 20, '2025-07-03'),
(5, 'USB-Cハブ', 'PC周辺機器', 4000, 3, '2025-07-03'),
(6, '伝統の筆', '文房具', 1200, 8, '2025-07-04'),
(7, '高級チョコレート', '食品', 3500, 5, '2025-07-05'),
(8, 'すごいボールペン', '文房具', 150, 15, '2025-07-05');
`;
db.run(setupSql);
executeBtn.disabled = false;
executeBtn.textContent = '実行';
resultOutput.innerHTML = '<p>準備完了!自由にSQLを試してみてください。</p>';
} catch (err) {
errorMsg.textContent = 'データベースの初期化に失敗しました: ' + err.message;
console.error(err);
}
}
function executeSql() {
if (!db) return;
const sql = sqlInput.value;
errorMsg.textContent = '';
resultOutput.innerHTML = '';
try {
const results = db.exec(sql);
if (results.length === 0) {
resultOutput.innerHTML = '<p>クエリは成功しましたが、結果セットは返されませんでした。</p>';
return;
}
results.forEach(result => {
const table = document.createElement('table');
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
const headerRow = document.createElement('tr');
result.columns.forEach(colName => {
const th = document.createElement('th');
th.textContent = colName;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
result.values.forEach(row => {
const bodyRow = document.createElement('tr');
row.forEach(cellValue => {
const td = document.createElement('td');
td.textContent = cellValue === null ? 'NULL' : cellValue.toLocaleString();
bodyRow.appendChild(td);
});
tbody.appendChild(bodyRow);
});
table.appendChild(thead);
table.appendChild(tbody);
resultOutput.appendChild(table);
});
} catch (err) {
errorMsg.textContent = 'SQLエラー: ' + err.message;
console.error(err);
}
}
executeBtn.addEventListener('click', executeSql);
initDb();
</script>
</body>
</html>
まとめ
今回は、データ分析の基本となる4つの集計関数、`SUM()`, `AVG()`, `MAX()`, `MIN()`について学びました。
- `SUM()`: 数値の合計を計算する。「総売上」「合計数量」など。
- `AVG()`: 数値の平均を計算する。「平均単価」「平均スコア」など。
- `MAX()`: 数値や日付などの最大値を見つける。「最高価格」「最新の日付」など。
- `MIN()`: 数値や日付などの最小値を見つける。「最低価格」「最も古い日付」など。
- 最強の武器 `GROUP BY`: これらの集計関数は、
GROUP BY句と組み合わせることで、グループごとの集計が可能になり、その真価を発揮する。 - 注意点: これらの集計関数は、計算の対象に`NULL`値を含めない。
これらの集計関数は、単にデータを取得するだけでなく、データから意味のある洞察を得るための第一歩です。ビジネス上の意思決定や、サイトの改善点の発見など、Webクリエーターとしても非常に強力な武器になります。
次に確認したいSQLページ
集計を使う場面では、前後の操作もセットで確認しておくと安全です。特に本番データを触る前は、件数確認、抽出条件、更新・削除の安全確認まで一連で見てください。