【Oracle】NVL / NVL2 / COALESCE / NULLIF 完全ガイド|NULL置換の使い分け・暗黙型変換・短絡評価・実務パターンまで解説

【Oracle】NVL / NVL2 / COALESCE / NULLIF 完全ガイド|NULL置換の使い分け・暗黙型変換・短絡評価・実務パターンまで解説 Oracle

Oracle で NULL を別の値に置き換えるには NVL 関数を使います。しかし Oracle には NVL のほかにも NVL2COALESCENULLIF と計 4 つの NULL 処理関数があり、それぞれに使いどころが異なります。

NVLCOALESCE はどう違うのか」「NVL で型変換エラーが出た」「SUM で NULL の行が無視されるのを防ぎたい」――こうした疑問は、4 関数の仕様を正確に理解すれば解消できます。

本記事では、NVL の基本から NVL2・COALESCE・NULLIF の使い分け、暗黙型変換の落とし穴COALESCE の短絡評価によるパフォーマンス差、そして計算式・文字列連結・集計関数での実務パターンまで体系的に解説します。

この記事でわかること
・NVL 関数の基本構文と動作
・NVL2 関数で「NULL の場合」と「NULL でない場合」を分岐する方法
・COALESCE 関数で複数の候補から最初の非 NULL を取得する方法
・NULLIF 関数で特定の値を NULL に変換する方法
・4 関数の比較表と使い分けの判断基準
・NVL の暗黙型変換の落とし穴
・COALESCE と NVL の短絡評価の違い(パフォーマンス)
・集計関数・計算式・文字列連結での NULL 処理パターン
スポンサーリンク

NVL 関数の基本

SQL(NVL 基本構文)
-- 構文: NVL(expr1, expr2)
-- expr1 が NULL なら expr2 を返す。NULL でなければ expr1 をそのまま返す

-- 数値: salary が NULL なら 0 に置き換え
SELECT employee_id, NVL(salary, 0) AS salary FROM employees;

-- 文字列: middle_name が NULL なら '(なし)' に置き換え
SELECT NVL(middle_name, '(なし)') AS middle_name FROM employees;

-- 日付: end_date が NULL なら現在日時に置き換え
SELECT NVL(end_date, SYSDATE) AS end_date FROM projects;
expr1 の値 NVL(expr1, 0) の結果 説明
500 500 expr1 が NULL でないのでそのまま返す
0 0 0 は NULL ではないのでそのまま返す
NULL 0 expr1 が NULL なので expr2(0)を返す
NVL の暗黙型変換に注意
NVL は第 2 引数の型を第 1 引数の型に暗黙変換します。型が一致しない場合にエラーが発生することがあります。
例: NVL(salary, 'なし') → salary が NUMBER 型なので’なし’ を NUMBER に変換しようとして ORA-01722: invalid number になります。型を揃えるか、NVL(TO_CHAR(salary), 'なし') と明示変換してください。

NVL2 関数:NULL と非 NULL で異なる値を返す

SQL(NVL2 基本)
-- 構文: NVL2(expr1, expr_not_null, expr_null)
-- expr1 が NULL でなければ expr_not_null を返す
-- expr1 が NULL なら expr_null を返す

-- commission_pct が NULL なら '固定給'、そうでなければ '歩合あり'
SELECT employee_id,
       NVL2(commission_pct, '歩合あり', '固定給') AS pay_type
FROM employees;

-- bonus が NULL なら 0、そうでなければ bonus * 1.1(10%増し)
SELECT employee_id,
       NVL2(bonus, bonus * 1.1, 0) AS adjusted_bonus
FROM employees;
NVL2 の引数の順序に注意
NVL2(expr, 非NULLの場合, NULLの場合) です。NVL とは引数の意味が逆順になりがちなので注意してください。「NVL2 の第 2 引数は NULL でない場合の値」と覚えます。

COALESCE 関数:複数の候補から最初の非 NULL を取得

SQL(COALESCE 基本)
-- 構文: COALESCE(expr1, expr2, expr3, ... , default)
-- 左から順に評価し、最初の非 NULL 値を返す

-- 携帯番号 → 自宅番号 → '連絡先なし' の優先順で取得
SELECT employee_id,
       COALESCE(mobile_phone, home_phone, '連絡先なし') AS contact
FROM employees;

-- NVL のネストを COALESCE で置き換え
-- 冗長: NVL(mobile_phone, NVL(home_phone, '連絡先なし'))
-- 簡潔: COALESCE(mobile_phone, home_phone, '連絡先なし')

COALESCE と NVL の違い:短絡評価

COALESCE短絡評価(ショートサーキット)を行います。最初の非 NULL が見つかった時点で残りの引数は評価しません。一方、NVL両方の引数を常に評価します。

SQL(短絡評価の違い)
-- NVL: expr2 が常に評価される(サブクエリも実行される)
SELECT NVL(name, (SELECT MAX(name) FROM employees)) FROM dual;
-- → name が NULL でなくても、サブクエリは実行される

-- COALESCE: 最初の非 NULL で停止(サブクエリは実行されない)
SELECT COALESCE(name, (SELECT MAX(name) FROM employees)) FROM dual;
-- → name が NULL でなければ、サブクエリは実行されない
パフォーマンスが重要な場面では COALESCE を推奨
第 2 引数にサブクエリや関数呼び出しがある場合、NVL は常にそれを実行するため不要な処理コストが発生します。COALESCE なら第 1 引数が非 NULL の行では第 2 引数を評価しないため高速です。また COALESCE は SQL 標準関数なので、他の RDBMS への移植性も高くなります。

NULLIF 関数:特定の値を NULL に変換する

SQL(NULLIF 基本)
-- 構文: NULLIF(expr1, expr2)
-- expr1 = expr2 なら NULL を返す。異なれば expr1 をそのまま返す

-- '(不明)' という文字列を NULL に変換
SELECT NULLIF(department_name, '(不明)') AS dept_name FROM departments;

-- 0 を NULL に変換(ゼロ除算の防止に便利)
SELECT total_amount / NULLIF(quantity, 0) AS unit_price
FROM order_details;
-- quantity が 0 なら NULL を返す → ORA-01476(ゼロ除算)を防止
NULLIF の最も実用的な使い方:ゼロ除算防止
a / NULLIF(b, 0) と書くと、b が 0 のときは a / NULL = NULL になり、ORA-01476(ゼロ除算)エラーを回避できます。CASE 文で書くより圧倒的にシンプルです。

NVL / NVL2 / COALESCE / NULLIF 比較表

関数 引数 動作 SQL 標準 短絡評価
NVL(a, b) 2 個 a が NULL なら b を返す × Oracle 独自 × 両方評価
NVL2(a, b, c) 3 個 a が NULL でなければ b、NULL なら c × Oracle 独自 × 全引数評価
COALESCE(a, b, c, …) 2 個以上 左から最初の非 NULL を返す ○ SQL 標準 ○ 短絡評価
NULLIF(a, b) 2 個 a = b なら NULL、異なれば a ○ SQL 標準
使い分けの判断基準
NULL を 1 つの代替値に置換NVL または COALESCE
NULL / 非 NULL で異なる値を返すNVL2
複数の候補から最初の非 NULL を選ぶCOALESCE
特定の値を NULL に変換(ゼロ除算防止等)NULLIF
他 RDBMS への移植性を考慮COALESCE(SQL 標準)

他 RDBMS との対応

RDBMS NULL 置換関数 複数候補からの選択
Oracle NVL(a, b) / NVL2(a, b, c) COALESCE(a, b, c, …)
MySQL IFNULL(a, b) COALESCE(a, b, c, …)
SQL Server ISNULL(a, b) COALESCE(a, b, c, …)
PostgreSQL (COALESCE のみ) COALESCE(a, b, c, …)
SQLite IFNULL(a, b) COALESCE(a, b, c, …)

COALESCE は全 RDBMS で共通に使えるため、移植性を重視する場合は NVL の代わりに COALESCE を使うのが安全です。

集計関数での NVL の使い方

SQL(集計関数と NVL)
-- SUM は NULL 行を無視する(0 として計算されない)
-- commission_pct: 10, NULL, 20, NULL → SUM = 30(NULL を無視)
SELECT SUM(commission_pct) FROM employees;

-- NULL を 0 として合計したい場合
SELECT SUM(NVL(commission_pct, 0)) FROM employees;
-- 10 + 0 + 20 + 0 = 30(結果は同じだが意味が明確)

-- AVG で影響が出るケース(NVL の有無で結果が変わる)
-- NVL なし: AVG = (10 + 20) / 2 = 15(NULL 行を除外して平均)
SELECT AVG(commission_pct) FROM employees;

-- NVL あり: AVG = (10 + 0 + 20 + 0) / 4 = 7.5(全行で平均)
SELECT AVG(NVL(commission_pct, 0)) FROM employees;
AVG での NVL は結果が大きく変わる
SUM では NVL の有無で結果は変わりませんが、AVG では分母が変わるため結果が大きく異なります。NULL 行を「値なし(除外)」として扱うのか「0 として扱う」のかを業務要件に応じて明確に判断してください。
SQL(COUNT での NULL)
-- COUNT(*): NULL を含む全行をカウント
SELECT COUNT(*) FROM employees;              -- 4(全行)

-- COUNT(col): NULL 以外の行のみカウント
SELECT COUNT(commission_pct) FROM employees;  -- 2(NULL を除外)

-- COUNT で NULL 行数を数える
SELECT COUNT(*) - COUNT(commission_pct) AS null_count FROM employees;

実務パターン集

パターン①:計算式での NULL 回避

SQL(NULL を含む計算)
-- NULL を含む計算は結果が NULL になる
SELECT 100 + NULL AS result FROM dual;   -- NULL
SELECT 100 * NULL AS result FROM dual;   -- NULL

-- NVL で NULL を 0 に置き換えて計算
SELECT
    employee_id,
    salary + NVL(bonus, 0) + NVL(allowance, 0) AS total_pay
FROM employees;

-- ゼロ除算の防止(NULLIF)
SELECT order_amount / NULLIF(order_count, 0) AS avg_amount
FROM order_summary;

パターン②:文字列連結での NULL 回避

SQL(文字列連結と NULL)
-- || 演算子: NULL が含まれると結果が NULL になることがある
-- Oracle では NULL || 'abc' = 'abc'(Oracle 独自仕様)
-- しかし明示的に NVL で処理する方が安全
SELECT
    last_name || ' ' || NVL(first_name, '') AS full_name
FROM employees;

-- COALESCE で優先順位付きの連結
SELECT
    COALESCE(nickname, first_name, 'ユーザー') || 'さん' AS display_name
FROM users;

パターン③:UPDATE で NULL を特定の値に一括変更

SQL(NULL の一括 UPDATE)
-- commission_pct が NULL の行を 0 に更新
UPDATE employees
SET commission_pct = 0
WHERE commission_pct IS NULL;

-- NVL を使ったパターン(NULLでない値はそのまま残す)
UPDATE employees
SET commission_pct = NVL(commission_pct, 0);
-- 結果は同じだが、WHERE なしで全行を処理するため件数が多くなる

パターン④:ORDER BY での NULL の位置制御

SQL(ORDER BY と NVL)
-- Oracle のデフォルト: ASC では NULL は末尾、DESC では NULL は先頭

-- NULLS FIRST / NULLS LAST で明示制御(推奨)
SELECT * FROM employees ORDER BY commission_pct ASC NULLS LAST;
SELECT * FROM employees ORDER BY commission_pct DESC NULLS LAST;

-- NVL を使ってソート順を制御する代替方法
-- NULL を最後にする(大きな値に置き換え)
SELECT * FROM employees ORDER BY NVL(commission_pct, 99999) ASC;

パターン⑤:DECODE と NVL の組み合わせ

SQL(DECODE + NVL)
-- DECODE は NULL を「等しい」として扱える(= 演算子とは異なる)
SELECT DECODE(commission_pct, NULL, '固定給', '歩合あり') FROM employees;
-- これは NVL2 と同じ動作

-- NVL + DECODE の組み合わせ
SELECT NVL(
    DECODE(status, 'A', '有効', 'I', '無効'),
    '不明'
) AS status_name
FROM users;

DECODE 関数の詳細は「DECODE関数の使い方完全解説」を参照してください。

よくある質問

QNVL と COALESCE はどちらを使うべきですか?
A基本的には COALESCE を推奨します。理由は 3 つです。①SQL 標準関数なので他の RDBMS にも移植可能、②短絡評価により不要な引数を評価しない(パフォーマンス向上)、③3 つ以上の候補を指定できる。NVL は Oracle 独自で 2 引数のみですが、可読性が高くコードが短いので、単純な NULL 置換なら NVL でも問題ありません。
QNVL で ORA-01722(invalid number)が出ます
ANVL は第 2 引数を第 1 引数の型に暗黙変換します。NVL(number_col, 'なし') のように NUMBER 列に文字列を渡すとエラーになります。型を揃えてください: NVL(TO_CHAR(number_col), 'なし')
QNVL(col, 0) と COALESCE(col, 0) の結果は同じですか?
Aほとんどのケースで同じ結果になりますが、型変換の動作が異なります。NVL は第 1 引数の型に合わせますが、COALESCE は引数間で共通の型を推定します。例: NVL(CHAR列, 123) は 123 を CHAR に変換しますが、COALESCE(CHAR列, 123) はエラーになることがあります。
QNVL2 の引数の順番がわかりません
ANVL2(判定値, 非NULLの場合, NULLの場合) です。「判定値が NULL でない場合」が第 2 引数(先に書く)です。NVL とは順番が逆になりがちなので、混乱しやすい場合は CASE WHEN を使う方が可読性が上がります。
Q集計関数で NULL をどう扱えばいいですか?
ASUM / AVG / MIN / MAX は NULL 行を自動的に除外します。SUM では NVL の有無で結果は変わりませんが、AVG では分母が変わるため結果が大きく異なります。NULL を 0 として扱いたい場合は AVG(NVL(col, 0)) と書き、NULL 行を除外したい場合はそのまま AVG(col) と書きます。
QNULLIF はどんなときに使いますか?
A最も実用的な場面はゼロ除算の防止です。a / NULLIF(b, 0) で b が 0 のとき NULL が返り、ゼロ除算エラーを回避できます。また、インポートデータで空文字列やプレースホルダー(例: ‘-‘)をNULL に変換するクレンジング処理にも使えます。

まとめ

Oracle の NULL 処理関数の要点をまとめます。

やりたいこと 推奨関数
NULL を代替値に置換 NVL(col, 代替値) または COALESCE(col, 代替値)
NULL / 非 NULL で異なる値を返す NVL2(col, 非NULL時の値, NULL時の値)
複数候補から最初の非 NULL を取得 COALESCE(a, b, c, …)
特定の値を NULL に変換 NULLIF(col, 特定値)
ゼロ除算を防止 a / NULLIF(b, 0)
計算式で NULL を 0 に salary + NVL(bonus, 0)
AVG で NULL を 0 として扱う AVG(NVL(col, 0))
他 RDBMS にも移植可能な書き方 COALESCE(SQL 標準)