【SQL】計算完全ガイド|算術演算子・数値関数・NULL計算の罠・型変換・条件付き計算・集計関数まで解説

【SQL】計算完全ガイド|算術演算子・数値関数・NULL計算の罠・型変換・条件付き計算・集計関数まで解説 SQL

SQL では列同士の計算・関数による変換・条件分岐を組み合わせた複雑な数値処理をクエリ 1 本で記述できます。プログラム側に持ち出す前にデータベース側で計算することで、転送データ量の削減とパフォーマンス向上が期待できます。

この記事では算術演算子から数値関数・NULL 計算の落とし穴・型変換・条件付き計算まで、SQL での計算に必要な知識を体系的に解説します。

スポンサーリンク

SQL で「計算」できるもの一覧

手段 概要
算術演算子 四則演算・余り salary * 1.1qty % 10
数値関数 丸め・絶対値・べき乗など ROUND(price, 2)ABS(diff)
型変換(CAST) 型を変えて計算精度を制御 CAST(5 AS DECIMAL) / 2
CASE 式 条件によって計算を切り替える CASE WHEN qty >= 10 THEN price * 0.9 ELSE price END
集計関数 グループ全体を集計する SUM(qty * unit_price)AVG(salary)
以降の例で使用するサンプルデータ
-- orders テーブル(注文)
-- order_id | product | qty | unit_price | discount | tax_rate
--        1 | りんご  |   5 |        200 |       10 |     0.10
--        2 | みかん  |  12 |        150 |        0 |     0.10
--        3 | ぶどう  |   3 |        500 |       50 |     0.10
--        4 | メロン  |   1 |       3000 |     NULL |     0.10

-- employees テーブル(従業員)
-- id | name      | salary | bonus | department
--  1 | 田中 太郎 |  55000 |  5000 | 営業
--  2 | 鈴木 花子 |  70000 |  8000 | 開発
--  3 | 高橋 美咲 |  80000 | 10000 | 開発
--  4 | 伊藤 健二 |  52000 |  NULL | 人事

算術演算子(+・-・*・/・%)

SQL の算術演算子は Excel の数式に近い感覚で使えます。SELECT 文の列リストや WHERE 句、ORDER BY 句でも使えます。

演算子 意味 結果
+ 加算 salary + bonus 給与 + ボーナス
- 減算 unit_price - discount 定価 – 割引額
* 乗算 qty * unit_price 数量 × 単価
/ 除算 salary / 12 月給 ÷ 12(年換算)
% 余り(剰余) order_id % 2 偶数/奇数の判定
MOD(a, b) 余り(関数版) MOD(qty, 10) qty を 10 で割った余り
算術演算子の基本例
-- 小計(数量 × 単価)、割引後金額、税込金額を一度に計算
SELECT
    product                              AS 商品名,
    qty                                  AS 数量,
    unit_price                           AS 単価,
    qty * unit_price                     AS 小計,
    qty * unit_price - discount          AS 割引後,
    (qty * unit_price - discount) * (1 + tax_rate) AS 税込金額
FROM orders;

-- 結果:
-- 商品名  | 数量 | 単価 | 小計  | 割引後 | 税込金額
-- ------+------+------+-------+--------+----------
-- りんご  |   5  |  200 |  1000 |    990 |   1089.0
-- みかん  |  12  |  150 |  1800 |   1800 |   1980.0
-- ぶどう  |   3  |  500 |  1500 |   1450 |   1595.0
-- メロン  |   1  | 3000 |  3000 |   NULL |      NULL  ← discount が NULL
演算子の優先順位に注意:
*/%+- より先に計算されます(数学と同じ)。意図した順序で計算させるには括弧 () を使ってください。
例: (unit_price - discount) * qtyunit_price - discount * qty は結果が全く異なります。
余り(MOD / %)の活用例
-- 偶数の order_id だけを取得
SELECT order_id, product FROM orders WHERE order_id % 2 = 0;
-- または: WHERE MOD(order_id, 2) = 0

-- ページネーションの総ページ数を計算
-- 総件数 7 件をページあたり 3 件表示する場合: CEIL(7/3.0) = 3
SELECT CEIL(COUNT(*) / 3.0) AS total_pages FROM orders;

-- 10個単位でのカート数確認(バラ(端数)の数量)
SELECT product, qty, MOD(qty, 10) AS remainder FROM orders;

整数除算の落とし穴と型変換(CAST)

SQL では整数 ÷ 整数 = 整数(小数切り捨て)になる RDBMS があります。意図した計算結果を得るには型変換が必要です。

整数除算の問題と解決策
-- NG: 整数どうしの除算(MySQL では小数が返るが RDBMS 依存)
SELECT 5 / 2;        -- MySQL: 2.5000  PostgreSQL: 2(切り捨て!)

-- OK: 一方を DECIMAL / FLOAT にキャストする
SELECT CAST(5 AS DECIMAL) / 2;   -- 2.5(すべての RDBMS で安全)
SELECT 5 / 2.0;                  -- 2.5(数値リテラルに小数点をつける)
SELECT 5 * 1.0 / 2;             -- 2.5(乗算で先に実数化する)

-- 実務例: 平均単価(整数割算に注意)
SELECT
    SUM(qty * unit_price)                        AS 総売上,
    COUNT(*)                                     AS 件数,
    CAST(SUM(qty * unit_price) AS DECIMAL) / COUNT(*) AS 平均単価
FROM orders;
RDBMS 5 / 2 の結果 CAST 後の結果
MySQL 2.5000(小数を返す) CAST(5 AS DECIMAL) / 2 → 2.5
PostgreSQL 2(整数切り捨て) 5::DECIMAL / 2 → 2.5
SQL Server 2(整数切り捨て) CAST(5 AS FLOAT) / 2 → 2.5
Oracle 2.5(小数を返す) TO_NUMBER(5) / 2 → 2.5
SQLite 2(整数切り捨て) 5.0 / 2 → 2.5
移植性を高めるコツ:

  • 割り算を書くときは必ず CAST(列 AS DECIMAL(10,2))列 * 1.0 で実数化する習慣をつける
  • PostgreSQL では 5::DECIMAL という短縮キャスト構文も使える
  • 精度が重要な金額計算では DECIMAL(15, 2) 等の固定小数点型を使い、浮動小数点(FLOAT)は避ける

NULL を含む計算の罠

NULL と任意の値を算術演算した結果は必ず NULL になります。これは SQL の仕様であり、しばしばバグの原因になります。

NULL 計算の挙動確認
-- discount が NULL のメロンは割引後も税込金額も NULL になる
SELECT
    product,
    unit_price - discount          AS 割引後,   -- 3000 - NULL = NULL
    unit_price * (1 + tax_rate)    AS 税込       -- 3000 * 1.1 = 3300(discount未使用なのでOK)
FROM orders
WHERE product = 'メロン';

-- salary + bonus でボーナスが NULL の場合も NULL になる
SELECT name, salary, bonus, salary + bonus AS 合計
FROM employees
WHERE name = '伊藤 健二';
-- → 合計: NULL(bonus が NULL のため)
NULL 計算の落とし穴:
NULL + 100 = NULLNULL * 0 = NULLNULL - NULL = NULL — NULL を含む計算はすべて NULLになります。「NULL は 0 として計算してほしい」場合は COALESCE または IFNULL で NULL を置き換えてから計算してください。
COALESCE で NULL を 0 に置換してから計算する
-- COALESCE(値, NULL のときの代替値)
-- bonus が NULL なら 0 として計算する
SELECT
    name,
    salary,
    bonus,
    salary + COALESCE(bonus, 0)     AS 合計    -- NULL を 0 に置換
FROM employees;

-- 結果:
-- 氏名        | salary | bonus | 合計
-- ----------+--------+-------+-------
-- 田中 太郎  |  55000 |  5000 |  60000
-- 鈴木 花子  |  70000 |  8000 |  78000
-- 高橋 美咲  |  80000 | 10000 |  90000
-- 伊藤 健二  |  52000 |  NULL |  52000  ← COALESCE で 0 に変換

-- discount が NULL のとき 0 として割引計算
SELECT
    product,
    unit_price - COALESCE(discount, 0) AS 割引後単価
FROM orders;

数値関数(ROUND・CEIL・FLOOR・ABS・POWER・SQRT)

SQL には計算結果の丸め・絶対値・べき乗などを扱う数値関数が組み込まれています。

関数 意味 結果
ROUND(n, d) n を小数第 d 位に四捨五入 ROUND(1234.567, 1) 1234.6
CEIL(n) / CEILING(n) n 以上の最小整数(切り上げ) CEIL(2.1) 3
FLOOR(n) n 以下の最大整数(切り捨て) FLOOR(2.9) 2
TRUNCATE(n, d) n を小数第 d 位以下を切り捨て(MySQL) TRUNCATE(2.987, 1) 2.9
ABS(n) 絶対値 ABS(-150) 150
MOD(n, m) n を m で割った余り MOD(17, 5) 2
POWER(n, p) / POW(n, p) n の p 乗 POWER(2, 10) 1024
SQRT(n) 平方根 SQRT(144) 12
SIGN(n) 正→1、0→0、負→-1 SIGN(-200) -1
ROUND / CEIL / FLOOR の使い分け
-- 税込価格を 1 円単位に丸める(四捨五入・切り上げ・切り捨て)
SELECT
    product,
    unit_price * 1.1                     AS 税込(小数あり),
    ROUND(unit_price * 1.1, 0)           AS 四捨五入,
    CEIL(unit_price * 1.1)               AS 切り上げ,
    FLOOR(unit_price * 1.1)              AS 切り捨て
FROM orders;

-- 結果:
-- 商品名 | 税込(小数あり)| 四捨五入 | 切り上げ | 切り捨て
-- りんご |          220.0 |      220 |      220 |      220
-- みかん |          165.0 |      165 |      165 |      165
-- ぶどう |          550.0 |      550 |      550 |      550

-- ページ数の計算(7件を3件ずつ表示する場合の総ページ数)
SELECT CEIL(COUNT(*) / 3.0) AS total_pages FROM orders;  -- 結果: 3

-- 差分の絶対値でソート(目標値との乖離が小さい順)
SELECT
    name, salary,
    ABS(salary - 60000) AS 目標との差
FROM employees
ORDER BY 目標との差;
TRUNCATE と ROUND の違い(MySQL)
-- ROUND: 四捨五入
SELECT ROUND(2.55, 1);    -- 2.6(銀行丸めの場合は 2.5 になる RDBMS もある)
SELECT ROUND(2.45, 1);    -- 2.5

-- TRUNCATE: 切り捨て(0 方向に向かう)
SELECT TRUNCATE(2.99, 1); -- 2.9(小数第2位以下を切り捨て)
SELECT TRUNCATE(-2.99, 1);-- -2.9(負の数も 0 方向に切り捨て)
-- MySQL固有: PostgreSQL では TRUNC(n, d)、SQL Server では ROUND(n, d, 1)

-- 注意: ROUND の「銀行丸め」
-- 一部 RDBMS(SQL Server など)は .5 を偶数方向に丸める(例: 2.5→2, 3.5→4)
-- 明示的な丸め方法を確認してから使うこと
TRUNCATE は MySQL 固有:
PostgreSQL では TRUNC(n, d)、SQL Server では ROUND(n, d, 1) を使います。移植性が必要な場合は FLOOR(n * 10^d) / 10^d のような算術式で代替できます。

CASE 式で条件によって計算を切り替える

CASE 式を使うと条件ごとに異なる計算を 1 クエリで表現できます。税率変更・割引ルール・ランク付けなど実務に直結します。

条件付き計算の基本(消費税率の分岐)
-- 軽減税率対応: 食品は 8%、それ以外は 10%
SELECT
    product,
    unit_price,
    CASE category
        WHEN '食品'  THEN ROUND(unit_price * 1.08, 0)
        WHEN '酒類'  THEN ROUND(unit_price * 1.10, 0)
        ELSE              ROUND(unit_price * 1.10, 0)
    END AS 税込価格
FROM products;

-- 数量による割引率の分岐(CASE WHEN)
SELECT
    product,
    qty,
    unit_price,
    CASE
        WHEN qty >= 10 THEN unit_price * 0.85   -- 10個以上は15%引き
        WHEN qty >=  5 THEN unit_price * 0.90   -- 5個以上は10%引き
        ELSE                unit_price           -- 定価
    END AS 割引後単価,
    qty * CASE
        WHEN qty >= 10 THEN unit_price * 0.85
        WHEN qty >=  5 THEN unit_price * 0.90
        ELSE                unit_price
    END AS 割引後小計
FROM orders;
CASE 式と集計関数の組み合わせ
-- 部門ごとの給与合計をピボット表示
SELECT
    SUM(CASE WHEN department = '営業' THEN salary ELSE 0 END) AS 営業合計,
    SUM(CASE WHEN department = '開発' THEN salary ELSE 0 END) AS 開発合計,
    SUM(CASE WHEN department = '人事' THEN salary ELSE 0 END) AS 人事合計,
    SUM(salary)                                               AS 全体合計
FROM employees;

-- 給与レンジ別の人数カウント
SELECT
    CASE
        WHEN salary < 55000 THEN '〜54,999'
        WHEN salary < 70000 THEN '55,000〜69,999'
        ELSE                     '70,000〜'
    END AS 給与レンジ,
    COUNT(*) AS 人数
FROM employees
GROUP BY
    CASE
        WHEN salary < 55000 THEN '〜54,999'
        WHEN salary < 70000 THEN '55,000〜69,999'
        ELSE                     '70,000〜'
    END
ORDER BY MIN(salary);

集計関数との組み合わせ

集計関数(SUM・AVG・MIN・MAX・COUNT)は列だけでなく計算式を引数に取れます。列を先に計算してから集計することで、複雑な集計を 1 クエリで表現できます。

集計関数と計算式の組み合わせ
-- SUM(式): 売上合計(数量 × 単価)
SELECT SUM(qty * unit_price) AS 売上合計 FROM orders;
-- → 1000 + 1800 + 1500 + 3000 = 7300

-- AVG(式): 割引後平均単価
SELECT AVG(unit_price - COALESCE(discount, 0)) AS 割引後平均単価 FROM orders;

-- 注文ごとの税込小計と全体合計
SELECT
    SUM(qty * unit_price)                         AS 税抜合計,
    SUM(ROUND(qty * unit_price * (1 + tax_rate))) AS 税込合計
FROM orders;

-- GROUP BY と組み合わせた部門別給与統計
SELECT
    department,
    COUNT(*)                        AS 人数,
    SUM(salary)                     AS 給与合計,
    ROUND(AVG(salary), 0)           AS 平均給与,
    MAX(salary) - MIN(salary)       AS 最大差
FROM employees
GROUP BY department
ORDER BY 給与合計 DESC;
各集計関数の詳しい使い方:
集計関数の NULL の扱い・DISTINCT との組み合わせ・ウィンドウ関数版の解説は各専門記事を参照してください:
SUM 完全ガイド ・AVG 完全ガイド ・MIN 完全ガイド ・COUNT 完全ガイド

実務でよく使う計算パターン集

割引率・粗利・達成率の計算
-- 割引率(%)を計算
SELECT
    product,
    discount,
    unit_price,
    ROUND(discount / CAST(unit_price AS DECIMAL) * 100, 1) AS 割引率
FROM orders
WHERE discount > 0;

-- 粗利と粗利率
-- cost(原価)列がある場合
SELECT
    product,
    unit_price - cost                                       AS 粗利,
    ROUND((unit_price - cost) / CAST(unit_price AS DECIMAL) * 100, 1) AS 粗利率
FROM products;

-- 達成率(目標 vs 実績)
SELECT
    name,
    actual_sales,
    target_sales,
    ROUND(actual_sales / CAST(target_sales AS DECIMAL) * 100, 1) AS 達成率
FROM sales_records;
累計・移動合計(ウィンドウ関数)
-- 日別売上の累計(PostgreSQL / MySQL 8.0+ / SQL Server)
SELECT
    order_date,
    daily_sales,
    SUM(daily_sales) OVER (ORDER BY order_date) AS 累計売上
FROM daily_summary
ORDER BY order_date;

-- 直近3日間の移動平均
SELECT
    order_date,
    daily_sales,
    ROUND(
        AVG(daily_sales) OVER (ORDER BY order_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW),
    0) AS 3日移動平均
FROM daily_summary
ORDER BY order_date;

-- 詳細は SUM 完全ガイドのウィンドウ関数セクションを参照
-- https://codingls.com/sql/2277/
ランクと分位(NTILE)の計算
-- 給与のランク付け(RANK と DENSE_RANK)
SELECT
    name,
    salary,
    RANK()       OVER (ORDER BY salary DESC) AS ランク,      -- 同順位あり(1,1,3)
    DENSE_RANK() OVER (ORDER BY salary DESC) AS 密ランク,    -- 同順位後も連続(1,1,2)
    ROW_NUMBER() OVER (ORDER BY salary DESC) AS 行番号       -- 必ず連番(1,2,3)
FROM employees;

-- 4 分位(上位 25%・50%・75%・100%)に分類
SELECT
    name,
    salary,
    NTILE(4) OVER (ORDER BY salary DESC) AS 分位
FROM employees;

RDBMS 別の計算まわりの注意点

機能 MySQL PostgreSQL SQL Server Oracle
整数÷整数 小数を返す 整数(切り捨て) 整数(切り捨て) 小数を返す
切り捨て関数 TRUNCATE(n,d) TRUNC(n,d) ROUND(n,d,1) TRUNC(n,d)
余り(剰余) MOD(n,m) / n%m MOD(n,m) / n%m n%m MOD(n,m)
べき乗 POWER(n,p) / POW(n,p) POWER(n,p) / n^p POWER(n,p) POWER(n,p)
絶対値 ABS(n) ABS(n) ABS(n) ABS(n)
NULL を 0 に IFNULL(n, 0) COALESCE(n, 0) ISNULL(n, 0) NVL(n, 0)
移植性を高めるための選択:

  • COALESCE(n, 0) は SQL 標準でほぼすべての RDBMS で使える(NULL 置換はこれに統一推奨)
  • 切り捨て関数は RDBMS ごとに異なるため、FLOOR(n * 10) / 10 で代替できる
  • 金額・税率計算は DECIMAL 型を使い、浮動小数点誤差(0.1 + 0.2 ≠ 0.3)を避ける

よくある質問(FAQ)

QSQL でパーセンテージ(割合)を計算すると 0 になってしまいます。
A整数どうしの除算で小数部分が切り捨てられている可能性があります。CAST(numerator AS DECIMAL) / denominator * 100 のように、分子を明示的に DECIMAL に変換してください。または numerator * 100.0 / denominator と数値リテラルに小数点をつける方法も有効です。
Q計算結果を WHERE 句で使いたいのですが、エラーになります。
AWHERE 句では SELECT で定義したエイリアスは使えません(SQL の実行順序:FROM→WHERE→SELECT の順)。WHERE 句に直接計算式を書いてください。例: WHERE qty * unit_price >= 1000。集計関数(SUM・COUNT 等)を条件にしたい場合は WHERE ではなく HAVING を使います。SQL の実行順序についてはSELECT文完全ガイドを参照してください。
QROUND 関数の結果が期待と違います(例: ROUND(2.5) が 2 になる)。
A一部の RDBMS(SQL Server など)は「銀行丸め(偶数丸め)」を使います。偶数丸めでは 2.5 は偶数の 2 に、3.5 は偶数の 4 に丸められます。常に .5 を切り上げたい場合は FLOOR(n + 0.5) で代替してください。MySQL と Oracle は .5 を常に切り上げる一般的な四捨五入を使います。
QNULL を含む列の合計を計算すると、その行だけ合計が NULL になります。
ANULL との算術演算は結果が必ず NULL になります。COALESCE(列, 0) で NULL を 0 に置換してから計算してください。一方、SUM()AVG() などの集計関数は NULL を無視して計算します(COUNT(*) を除く)。つまり SUM(bonus) は bonus が NULL の行を自動的に除外して合計します。
Q小数の計算で 0.1 + 0.2 の結果が 0.30000000000000004 になります。
A浮動小数点型(FLOAT・DOUBLE)は 2 進数で内部表現されるため、0.1 や 0.2 を正確に表現できず誤差が生じます。金額・税率など精度が重要な計算には DECIMAL(15, 4) のような固定小数点型を使ってください。ROUND(0.1 + 0.2, 2) のように最後に丸めることで表示上の誤差を回避することもできます。

まとめ

やりたいこと 使う手段
四則演算(+・-・*・/) 算術演算子をそのまま列名や定数に適用
余り(偶数判定・端数計算) MOD(n, m) または n % m
整数÷整数で小数を得る CAST(n AS DECIMAL) / m または n / m * 1.0
NULL を 0 として計算する COALESCE(列, 0) で NULL を置換してから演算
小数の丸め(四捨五入) ROUND(n, d)
切り上げ・切り捨て CEIL(n) / FLOOR(n)(切り捨ては RDBMS ごとに関数名が違う)
絶対値・べき乗・平方根 ABS(n)POWER(n, p)SQRT(n)
条件によって計算を切り替える CASE WHEN 条件 THEN 計算式 ELSE 別の計算式 END
複数行を集計して計算する SUM(式)AVG(式) などの集計関数
金額計算で精度を保証する FLOAT ではなく DECIMAL 型を使う