【Oracle】ORA-01476の原因と解決方法|divisor is equal to zero・ゼロ除算エラーの直し方

ORA-01476: divisor is equal to zero は、Oracleで割り算の分母が0になったときに発生するエラーです。日本語にすると「除数が0です」「ゼロ除算です」という意味です。

発生しやすいのは、割合、達成率、前年比、平均単価、使用率、構成比などをSQLで計算している場面です。分母になる件数、金額、数量、容量が0になる行が混ざると、1行だけでもSQL全体がエラーになります。

先に結論
ORA-01476は、まず割り算の分母が0になる行を探します。単純にNULLを0に置換するのではなく、NULLIF(denominator, 0) で0をNULLにして割る、または CASE WHEN denominator = 0 THEN ... ELSE numerator / denominator END のように、0の時の業務上の扱いを明示して直します。
スポンサーリンク

ORA-01476とは

Oracle公式のエラー説明では、ORA-01476は「式が0で割り算をしようとした」状態です。原因はかなり明確で、/ 演算子の右側、つまり分母が0です。

ただし実務では、SQLが長かったり、サブクエリや集計結果を分母にしていたりして、どこで0除算が起きているか見つけにくいことがあります。まずは割り算をしている箇所を洗い出し、分母候補が0になる行を確認します。

発生しやすい計算 分母になりやすい値
達成率 目標値 actual / target * 100
平均単価 数量 amount / quantity
構成比 全体件数・全体金額 count / total_count
前年比 前年値 (this_year - last_year) / last_year
使用率 総容量 used_size / total_size

まず分母が0の行を探す

エラーを直す前に、どの行で分母が0になっているか確認します。たとえば平均単価を amount / quantity で計算しているなら、quantity = 0 の行を探します。

find-zero-denominator.sql
SELECT order_id,
       amount,
       quantity
FROM order_items
WHERE quantity = 0;

分母が式になっている場合は、その式をSELECTして確認します。分母に SUMCOUNT を使っている場合は、集計後の値が0になるグループを探します。

find-zero-aggregate-denominator.sql
SELECT department_id,
       SUM(target_amount) AS total_target
FROM sales_targets
GROUP BY department_id
HAVING SUM(target_amount) = 0;

集計SQLの基本は GROUP BYで件数をカウントする方法、合計計算は SUM関数の使い方 も参考になります。

長いSQLでは割り算を分解して確認する

SQLが長い場合、どの割り算でORA-01476が出ているかわからないことがあります。そのときは、いきなり式を直すのではなく、分子と分母を別名でSELECTし、分母が0の行だけを外側のSQLで絞り込みます。

debug-denominator-with-subquery.sql
WITH calc_base AS (
    SELECT department_id,
           SUM(actual_amount) AS numerator,
           SUM(target_amount) AS denominator
    FROM sales_results
    GROUP BY department_id
)
SELECT *
FROM calc_base
WHERE denominator = 0;

原因が見つかったら、同じサブクエリを使って安全な割り算に書き換えます。複雑な計算式では、分子・分母に名前を付けるだけでレビューしやすくなります。

safe-division-with-subquery.sql
WITH calc_base AS (
    SELECT department_id,
           SUM(actual_amount) AS numerator,
           SUM(target_amount) AS denominator
    FROM sales_results
    GROUP BY department_id
)
SELECT department_id,
       numerator,
       denominator,
       ROUND(numerator / NULLIF(denominator, 0) * 100, 2) AS rate
FROM calc_base;

NULLIFで0除算を避ける

もっとも短く書ける対処は NULLIF です。NULLIF(quantity, 0) は、quantity が0ならNULL、それ以外なら元の値を返します。Oracleでは分母がNULLなら結果もNULLになり、ORA-01476にはなりません。

nullif-safe-division.sql
-- NG: quantity が0の行でORA-01476
SELECT order_id,
       amount / quantity AS unit_price
FROM order_items;

-- OK: quantity が0なら計算結果をNULLにする
SELECT order_id,
       amount / NULLIF(quantity, 0) AS unit_price
FROM order_items;

NULLIF は、「分母が0なら計算不能としてNULLにする」方針に向いています。0を返したいのか、NULLにしたいのか、該当行を除外したいのかは、業務上の意味で決めます。NULL処理の基本は OracleのNULL処理関数 にまとめています。

CASEで0の時の値を明示する

分母が0のときにNULLではなく0、または固定の表示値を返したい場合は CASE を使います。どの値を返すかを明示できるため、帳票や画面表示ではこちらのほうが読みやすいことがあります。

case-safe-division.sql
SELECT order_id,
       CASE
           WHEN quantity = 0 THEN NULL
           ELSE amount / quantity
       END AS unit_price
FROM order_items;

たとえば達成率で、目標が0の行を0%として表示したいなら次のように書けます。ただし、目標が0なら0%なのか、計算不能としてNULLなのかは業務ルール次第です。

case-rate-zero.sql
SELECT user_id,
       actual_amount,
       target_amount,
       CASE
           WHEN target_amount = 0 THEN 0
           ELSE ROUND(actual_amount / target_amount * 100, 2)
       END AS achievement_rate
FROM sales_results;

NVLやCOALESCEを使う位置に注意する

NVLCOALESCE はNULLを置き換える関数ですが、使う位置を間違えるとORA-01476を防げません。割り算を評価した後にNULL置換しても、先に0除算が発生すればエラーになります。

nvl-position-bad-good.sql
-- NG: 先に amount / quantity が評価されるため、quantity=0ならORA-01476
SELECT NVL(amount / quantity, 0) AS unit_price
FROM order_items;

-- OK: 分母の0をNULLにしてから割る
SELECT NVL(amount / NULLIF(quantity, 0), 0) AS unit_price
FROM order_items;

また、NVL(quantity, 0) のように分母側のNULLを0へ置換すると、NULLだった分母まで0になり、ORA-01476の原因になります。分母のNULLや0をどう扱うかは、計算前に整理しておきます。

WHEREで分母0の行を除外する

分母が0の行を結果から除外してよいなら、WHERE で絞る方法もあります。ただし、行が消えるため、件数や集計値が変わります。帳票や分析では、除外した行数も別途確認できるようにしておくと安全です。

where-denominator-not-zero.sql
SELECT order_id,
       amount / quantity AS unit_price
FROM order_items
WHERE quantity <> 0;

集計SQLで割合を出す場合

構成比や達成率のように、集計した結果を割るSQLでもORA-01476は発生します。分母になる SUMCOUNT が0になる可能性を考慮します。

safe-aggregate-rate.sql
SELECT department_id,
       SUM(actual_amount) AS actual_total,
       SUM(target_amount) AS target_total,
       ROUND(
           SUM(actual_amount) / NULLIF(SUM(target_amount), 0) * 100,
           2
       ) AS achievement_rate
FROM sales_results
GROUP BY department_id;

平均を出す目的なら、自前で SUM(amount) / COUNT(*) と書くより、AVG(amount) を使えるケースもあります。平均値の扱いは AVG関数の使い方 を確認してください。

前年比や増減率で発生するケース

前年比や増減率では、前年値が0のときにORA-01476が発生します。前年売上が0で今年売上がある場合、増減率を何%とみなすかは業務上の定義が必要です。単に0へ置換すると、意味の違う指標になることがあります。

year-over-year-rate.sql
-- 前年値が0なら増減率をNULLにする例
SELECT product_id,
       this_year_amount,
       last_year_amount,
       ROUND(
           (this_year_amount - last_year_amount)
           / NULLIF(last_year_amount, 0) * 100,
           2
       ) AS yoy_rate
FROM product_sales;

画面表示でNULLを「-」や「対象外」と出したい場合は、SQLで数値を文字列に変えるより、アプリや帳票側で表示変換するほうが後続の集計に使いやすいことが多いです。

構成比で全体が0になるケース

構成比では、全体合計が0になると分母が0になります。全体が0ということは、比率を計算しても意味がない場合が多いため、NULLや対象外として扱う設計が自然です。

composition-ratio-zero-total.sql
SELECT category,
       amount,
       ROUND(
           amount / NULLIF(SUM(amount) OVER (), 0) * 100,
           2
       ) AS composition_ratio
FROM category_sales;

分析関数で割合を出す場合

明細行を残したまま全体比率を出す場合、分析関数の結果を分母にすることがあります。この場合も、分析関数の結果が0になる可能性を考えます。

safe-analytic-rate.sql
SELECT department_id,
       employee_id,
       amount,
       ROUND(
           amount / NULLIF(SUM(amount) OVER (PARTITION BY department_id), 0) * 100,
           2
       ) AS dept_ratio
FROM sales;

分析関数の基本は Oracleの分析関数の使い方 も参考になります。

PL/SQLで発生するケース

ORA-01476はSQLだけでなくPL/SQLの計算でも発生します。例外処理で握りつぶすより、まず分母をチェックしてから割り算するほうが原因がわかりやすく、安全です。

plsql-zero-divide.sql
DECLARE
    v_amount   NUMBER := 100;
    v_quantity NUMBER := 0;
    v_price    NUMBER;
BEGIN
    IF v_quantity = 0 THEN
        v_price := NULL;
    ELSE
        v_price := v_amount / v_quantity;
    END IF;
END;

PL/SQLの例外処理でログを残す場合は PL/SQL例外処理の基本、数値計算や代入で別のエラーが出る場合は ORA-06502の原因と解決方法 も確認してください。

0を返すべきかNULLを返すべきか

ORA-01476の修正で大事なのは、エラーを消すだけでなく、分母0の意味を決めることです。たとえば「売上0円の平均単価」は0でよい場合もありますが、「目標0円に対する達成率」は0%ではなく計算不能としてNULLのほうが自然な場合があります。

返す値 向いているケース 注意点
NULL 計算不能として扱いたい 画面・帳票でNULL表示をどうするか決める
0 0として集計・表示したい 本当に0の意味でよいか確認する
行を除外 分母0の行を対象外にしたい 件数や合計が変わる
別ラベル 画面で「対象外」「未設定」と出したい SQLでは文字列型になる場合がある

ORA-01476とORA-06502の違い

ORA-01476は0除算そのもののエラーです。一方、ORA-06502はPL/SQLの数値・値エラーで、桁あふれ、文字列バッファ不足、型変換失敗などでも発生します。割り算の分母が0ならORA-01476、計算結果の代入先が小さすぎるなどならORA-06502を疑います。

エラー 主な原因 見る場所
ORA-01476 分母が0 / 演算子の右側
ORA-06502 数値・文字列・変換エラー PL/SQL変数、NUMBER精度、VARCHAR2長

修正チェックリスト

手順 確認すること 判断
1 SQLやPL/SQL内の割り算を探す / の右側が分母
2 分母が0になる行をSELECTする WHERE denominator = 0
3 分母が集計式ならHAVINGで確認する HAVING SUM(x) = 0
4 0の時の業務上の意味を決める NULL、0、除外、別ラベル
5 短く直すならNULLIFを使う numerator / NULLIF(denominator, 0)
6 条件を明示するならCASEを使う CASE WHEN denominator = 0 THEN ...
7 NVL/COALESCEの位置を確認する 割り算の前に分母0を処理する

よくある質問

NULLIFを使うと結果はどうなりますか?

分母が0のとき、NULLIF によって分母がNULLになり、割り算の結果もNULLになります。エラーは避けられますが、結果を0にしたい場合は外側で NVL(..., 0) などを使います。

NVL(amount / quantity, 0) ではだめですか?

だめな場合があります。amount / quantity が先に評価されるため、quantity = 0 ならNVLで置換する前にORA-01476になります。amount / NULLIF(quantity, 0) のように分母側を先に処理します。

分母がNULLの場合もORA-01476になりますか?

通常、分母がNULLなら結果はNULLになり、0除算エラーにはなりません。ただし、NVL(denominator, 0) のようにNULLを0へ置換してから割るとORA-01476の原因になります。

0を返すのとNULLを返すのはどちらがよいですか?

業務上の意味で決めます。計算不能ならNULL、0として扱うのが正しい指標なら0です。達成率や前年比では、安易に0へ置換すると判断を誤ることがあります。

WHERE denominator <> 0 で除外してもよいですか?

除外してよい行なら有効です。ただし結果件数や集計対象が変わるため、除外された行があることを把握できるようにしておくと安全です。

まとめ

ORA-01476は、Oracleで分母が0の割り算を実行したときに発生します。まず割り算の箇所を探し、分母が0になる行やグループを特定します。

計算不能をNULLで表すなら NULLIF(denominator, 0)、0や別の値を返したいなら CASE で業務ルールを明示します。NVLCOALESCE は便利ですが、割り算の後ではなく分母の処理に使うことが重要です。

参考

ORA-01476 – Oracle Database Error Help

NULLIF – Oracle SQL Language Reference