🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

【SQL関数入門】SUM, AVG, MAX, MINを使いこなし、データ集計の達人になる!

Webサイトの売上レポートを作成する際、「今月の総売上はいくら?」「商品の平均単価は?」「一番高く売れた商品は何?」といった情報は不可欠です。データベースに蓄積された個々のデータを、意味のある一つの数値に集約して取り出したい――そんなときに絶大なパワーを発揮するのが、SQLの集計関数です。

集計関数とは、複数の行にまたがるデータを入力として受け取り、その集計結果として単一の値を返す関数のことです。例えるなら、たくさんの数字が書かれた紙を電卓に読み込ませて、「合計」や「平均」といった一つの答えを出力させるようなものです。

この記事では、数ある集計関数の中でも特に使用頻度が高く、データ分析の基本となる「四天王」、SUM(), AVG(), MAX(), MIN() の使い方を、コピペで動くコードと共に徹底的に解説します。これらの関数をマスターし、`GROUP BY`と組み合わせることで、あなたのデータ分析能力は飛躍的に向上するでしょう!


準備:集計対象の売上データを用意しよう

集計関数を試すには、集計対象となる数値データが必要です。今回は、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`を組み合わせることで、単なる数字の羅列だった生データから、ビジネスに役立つ「インサイト」を引き出すことができるのです。


【体験コーナー】ブラウザで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()`について学びました。

これらの集計関数は、単にデータを取得するだけでなく、データから意味のある洞察を得るための第一歩です。ビジネス上の意思決定や、サイトの改善点の発見など、Webクリエーターとしても非常に強力な武器になります。ぜひ、これらの関数を使いこなし、データと対話する楽しさを感じてみてください!