「計算結果がNULLになって困る…」 「NULLが含まれるとレポートが正しく表示されない」 「IF文をたくさん書かないとNULL処理ができない」
データベースを扱っていると、NULL値は必ず出てくる厄介者。
でも大丈夫!PostgreSQLのCOALESCE関数を使えば、NULL処理が驚くほどシンプルになります。
この記事を読み終える頃には、あなたもNULL処理のエキスパートになっているはずです!
COALESCE関数を一言で説明すると?

超簡単な説明
**COALESCE(コアレス)**は、「最初に見つかったNULLじゃない値を返す」関数です。
日常生活に例えると:
- 第1希望のレストランが満席 → 第2希望へ
- 第2希望も満席 → 第3希望へ
- 空いているレストランが見つかったら、そこに決定!
COALESCEも同じように、NULL(空席)をスキップして、最初の値(空いている店)を返します。
基本的な書き方
COALESCE(値1, 値2, 値3, ...)
左から順番にチェックして、最初のNULLじゃない値を返します。
具体例:
SELECT COALESCE(NULL, NULL, 'やっと見つかった!', 'これも候補');
-- 結果: 'やっと見つかった!'
実際のテーブルで理解する:基本編
サンプルテーブルを作ろう
まず、従業員テーブルで実例を見ていきましょう:
-- 従業員テーブルの作成
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
mobile_phone VARCHAR(20),
office_phone VARCHAR(20),
home_phone VARCHAR(20),
email VARCHAR(100)
);
-- サンプルデータの挿入
INSERT INTO employees (name, mobile_phone, office_phone, home_phone, email) VALUES
('田中太郎', '090-1234-5678', '03-1234-5678', NULL, 'tanaka@example.com'),
('佐藤花子', NULL, '03-2345-6789', '044-123-4567', 'sato@example.com'),
('鈴木一郎', NULL, NULL, '045-234-5678', 'suzuki@example.com'),
('高橋美咲', '080-3456-7890', NULL, NULL, 'takahashi@example.com'),
('山田次郎', NULL, NULL, NULL, 'yamada@example.com');
基本的な使い方:連絡先を1つ表示
問題: 従業員の連絡先電話番号を表示したい。優先順位は携帯→会社→自宅。
SELECT
name AS 名前,
COALESCE(mobile_phone, office_phone, home_phone, '電話番号なし') AS 連絡先
FROM employees;
結果:
名前 | 連絡先
------------|------------------
田中太郎 | 090-1234-5678
佐藤花子 | 03-2345-6789
鈴木一郎 | 045-234-5678
高橋美咲 | 080-3456-7890
山田次郎 | 電話番号なし
素晴らしい!複雑なCASE文なしで、優先順位付きの処理ができました。
実践的な使用例:これができれば業務で困らない!
1. 売上レポートでNULL対策
売上データにNULLがあると、合計が正しく計算されません:
-- 売上テーブル
CREATE TABLE sales (
product_name VARCHAR(100),
quantity INTEGER,
unit_price DECIMAL(10,2),
discount DECIMAL(10,2)
);
INSERT INTO sales VALUES
('商品A', 10, 1000, 100),
('商品B', 5, 2000, NULL),
('商品C', NULL, 1500, 200),
('商品D', 8, NULL, NULL);
NULL対策なしの計算(間違い):
SELECT
product_name,
quantity * unit_price - discount AS 売上金額
FROM sales;
-- NULLが含まれると結果もNULLに!
COALESCE使用(正解):
SELECT
product_name AS 商品名,
COALESCE(quantity, 0) AS 数量,
COALESCE(unit_price, 0) AS 単価,
COALESCE(discount, 0) AS 割引,
COALESCE(quantity, 0) * COALESCE(unit_price, 0) - COALESCE(discount, 0) AS 売上金額
FROM sales;
結果:
商品名 | 数量 | 単価 | 割引 | 売上金額
-------|-----|-------|------|--------
商品A | 10 | 1000 | 100 | 9900
商品B | 5 | 2000 | 0 | 10000
商品C | 0 | 1500 | 200 | -200
商品D | 8 | 0 | 0 | 0
2. 文字列の結合でNULL対策
住所を結合する時のNULL処理:
-- 住所テーブル
CREATE TABLE addresses (
id SERIAL PRIMARY KEY,
prefecture VARCHAR(50),
city VARCHAR(50),
street VARCHAR(100),
building VARCHAR(100)
);
INSERT INTO addresses (prefecture, city, street, building) VALUES
('東京都', '渋谷区', '道玄坂1-1-1', 'ABCビル5F'),
('神奈川県', '横浜市', '西区2-2-2', NULL),
('', '名古屋市', '中区3-3-3', NULL),
(NULL, NULL, NULL, 'XYZマンション');
スマートな住所表示:
SELECT
id,
COALESCE(
NULLIF(prefecture, '') ||
COALESCE(' ' || NULLIF(city, ''), '') ||
COALESCE(' ' || NULLIF(street, ''), '') ||
COALESCE(' ' || NULLIF(building, ''), ''),
'住所未登録'
) AS 完全住所
FROM addresses;
3. デフォルト値の設定
ユーザー設定にデフォルト値を適用:
-- ユーザー設定テーブル
CREATE TABLE user_settings (
user_id INTEGER PRIMARY KEY,
theme VARCHAR(20),
language VARCHAR(10),
notifications BOOLEAN,
items_per_page INTEGER
);
INSERT INTO user_settings VALUES
(1, 'dark', 'ja', true, 50),
(2, NULL, 'en', NULL, NULL),
(3, 'light', NULL, false, 100);
デフォルト値を適用:
SELECT
user_id,
COALESCE(theme, 'light') AS テーマ,
COALESCE(language, 'ja') AS 言語,
COALESCE(notifications, true) AS 通知,
COALESCE(items_per_page, 20) AS 表示件数
FROM user_settings;
COALESCEと他の関数の使い分け
COALESCE vs CASE文
CASE文での書き方(長い):
SELECT
CASE
WHEN mobile_phone IS NOT NULL THEN mobile_phone
WHEN office_phone IS NOT NULL THEN office_phone
WHEN home_phone IS NOT NULL THEN home_phone
ELSE '電話番号なし'
END AS 連絡先
FROM employees;
COALESCEでの書き方(短い):
SELECT
COALESCE(mobile_phone, office_phone, home_phone, '電話番号なし') AS 連絡先
FROM employees;
COALESCEの方が圧倒的に簡潔!
COALESCE vs NULLIF
NULLIFは逆の動作をします:
-- NULLIFは、2つの値が同じならNULLを返す
SELECT NULLIF('同じ', '同じ'); -- 結果: NULL
SELECT NULLIF('違う', '別'); -- 結果: '違う'
-- 組み合わせて使うと強力!
-- 空文字をNULLに変換してから、デフォルト値を設定
SELECT COALESCE(NULLIF(column_name, ''), 'デフォルト値');
COALESCE vs GREATEST/LEAST
-- COALESCEは最初の非NULL値
SELECT COALESCE(NULL, 10, 20, 5); -- 結果: 10
-- GREATESTは最大値(NULLがあると結果もNULL)
SELECT GREATEST(10, 20, 5); -- 結果: 20
SELECT GREATEST(NULL, 10, 20); -- 結果: NULL
-- 組み合わせて使う
SELECT GREATEST(COALESCE(col1, 0), COALESCE(col2, 0), COALESCE(col3, 0));
パフォーマンスを考慮した使い方
インデックスとの関係
注意点: COALESCEを使うと、インデックスが効かなくなる場合があります。
-- インデックスが効かない例
SELECT * FROM employees
WHERE COALESCE(mobile_phone, office_phone) = '090-1234-5678';
-- インデックスが効く書き方
SELECT * FROM employees
WHERE mobile_phone = '090-1234-5678'
OR (mobile_phone IS NULL AND office_phone = '090-1234-5678');
大量データでの注意点
-- 非効率な書き方(全行でCOALESCE実行)
SELECT COUNT(*)
FROM large_table
WHERE COALESCE(status, 'pending') = 'active';
-- 効率的な書き方(部分インデックス使用)
CREATE INDEX idx_active_status ON large_table(status)
WHERE status = 'active';
SELECT COUNT(*)
FROM large_table
WHERE status = 'active';
よくある間違いと対処法

間違い1:空文字とNULLの混同
-- 問題のあるデータ
INSERT INTO test_table (name) VALUES
(NULL), -- NULL
(''), -- 空文字
(' '); -- スペース
-- 空文字はNULLじゃない!
SELECT COALESCE(name, 'デフォルト') FROM test_table;
-- 結果: 'デフォルト', '', ' '
-- 正しい対処法
SELECT COALESCE(NULLIF(TRIM(name), ''), 'デフォルト') FROM test_table;
-- 結果: 'デフォルト', 'デフォルト', 'デフォルト'
間違い2:データ型の不一致
-- エラーになる例
SELECT COALESCE(NULL, 'テキスト', 123);
-- ERROR: COALESCE型が一致しません
-- 正しい書き方(型を合わせる)
SELECT COALESCE(NULL, 'テキスト', '123');
-- または
SELECT COALESCE(NULL::TEXT, 'テキスト', 123::TEXT);
間違い3:全部NULLの場合
-- 全部NULLだと結果もNULL
SELECT COALESCE(NULL, NULL, NULL);
-- 結果: NULL
-- 必ず最後にデフォルト値を入れる
SELECT COALESCE(col1, col2, col3, 'デフォルト値');
応用テクニック:上級者への道
動的なデフォルト値
-- 現在の日付をデフォルトに
SELECT COALESCE(created_at, CURRENT_DATE) AS 作成日;
-- 他のカラムの値をデフォルトに
SELECT COALESCE(nickname, first_name, 'ゲスト') AS 表示名;
サブクエリと組み合わせ
-- 部署の平均給与をデフォルトに
SELECT
name,
COALESCE(
salary,
(SELECT AVG(salary) FROM employees WHERE dept_id = e.dept_id)
) AS 給与
FROM employees e;
配列でのCOALESCE
-- 配列要素のNULL処理
SELECT COALESCE(array_column[1], array_column[2], 'デフォルト');
-- 配列全体のNULL処理
SELECT COALESCE(array_column, ARRAY['デフォルト1', 'デフォルト2']);
JSONでのCOALESCE
-- JSONフィールドのNULL処理
SELECT COALESCE(
json_data->>'email',
json_data->>'alternative_email',
'no-email@example.com'
) AS メールアドレス;
実務でよく使うパターン集
レポート生成
-- 月次売上レポート
SELECT
month,
COALESCE(SUM(sales_amount), 0) AS 売上合計,
COALESCE(AVG(sales_amount), 0) AS 平均売上,
COALESCE(COUNT(NULLIF(sales_amount, 0)), 0) AS 売上件数
FROM monthly_sales
GROUP BY month;
ユーザー表示名の生成
-- 優先順位: ニックネーム → フルネーム → メールアドレスの@前 → 'ユーザー'
SELECT
COALESCE(
nickname,
first_name || ' ' || last_name,
SPLIT_PART(email, '@', 1),
'ユーザー'
) AS 表示名
FROM users;
ステータス管理
-- ステータスの優先順位付け
SELECT
order_id,
COALESCE(
CASE WHEN cancelled_at IS NOT NULL THEN 'キャンセル済' END,
CASE WHEN shipped_at IS NOT NULL THEN '発送済' END,
CASE WHEN paid_at IS NOT NULL THEN '支払済' END,
'処理中'
) AS ステータス
FROM orders;
まとめ:COALESCEでNULL処理をマスター!
今日学んだポイントを振り返りましょう:
✅ COALESCE = 最初の非NULL値を返す関数 ✅ 基本構文:COALESCE(値1, 値2, ..., デフォルト値)
✅ CASE文より簡潔に書ける ✅ 計算や文字列結合でNULL対策必須 ✅ 空文字とNULLは違うので注意 ✅ データ型を統一する必要がある ✅ インデックスへの影響を考慮
COALESCEは、PostgreSQLでNULL処理をする時の最強の味方です。
最初は「NULL処理って面倒…」と感じるかもしれません。でも、COALESCEを使いこなせば、エレガントで読みやすいSQLが書けるようになります。
今日から早速、あなたのSQLにCOALESCEを取り入れてみてください。NULL値に悩まされる日々から、きっと解放されるはずです!
Happy Coding!
次のステップにおすすめ:
- PostgreSQLのNULL関連関数まとめ
- CASE文の高度な使い方
- PostgreSQLパフォーマンスチューニング
コメント