SQLの3項演算子とは?CASE式で条件分岐を使いこなす完全ガイド

データベース・SQL

「条件によって表示する値を変えたい」「ステータスコードを分かりやすいテキストに変換したい」「NULL値を別の値に置き換えたい」…。

プログラミング言語には、条件によって値を切り替える3項演算子という便利な機能がありますよね。

実は、SQLにも同じような機能があるんです。それがCASE式です。

厳密には「3項演算子」という用語はSQLには存在しませんが、他のプログラミング言語の3項演算子と同じように、条件に応じて異なる値を返すことができます。CASE式を使えば、複雑な条件分岐も柔軟に表現できるんです。

この記事では、SQLで条件分岐を行う方法を、初心者の方にも分かりやすく解説していきます。

スポンサーリンク

3項演算子とは?基本を理解しよう

まずは、3項演算子の概念から確認していきましょう。

他のプログラミング言語の3項演算子

多くのプログラミング言語には、3項演算子(三項演算子)があります。

JavaScript の例

// 条件 ? 真の場合の値 : 偽の場合の値
const result = age >= 18 ? "成人" : "未成年";

PHP の例

$message = $score >= 60 ? "合格" : "不合格";

Python の例

result = "合格" if score >= 60 else "不合格"

3項演算子の特徴

3項演算子には、以下の特徴があります。

特徴説明
簡潔if-else文をコンパクトに書ける
式として評価値を返すので、変数への代入や関数の引数に使える
可読性シンプルな条件なら読みやすい

SQLにおける同等機能

SQLには「3項演算子」という構文はありませんが、同等の機能を持つものがいくつかあります。

  • CASE式:最も汎用的で強力
  • IF関数(MySQL):シンプルな条件分岐
  • IIF関数(SQL Server、Access):2値の選択
  • COALESCE関数:NULL値の処理
  • NULLIF関数:特定値をNULLに変換

CASE式の基本

SQLで条件分岐を行う最も標準的な方法が、CASE式です。

CASE式とは

CASE式は、条件に応じて異なる値を返すSQL標準の構文です。

すべての主要なデータベース管理システムでサポートされています。

基本構文(単純CASE式)

値が特定の値と一致するかを判定します。

CASE 評価する列
    WHEN 値1 THEN 結果1
    WHEN 値2 THEN 結果2
    WHEN 値3 THEN 結果3
    ELSE デフォルト結果
END

使用例

SELECT 
    name,
    CASE status
        WHEN 0 THEN '未処理'
        WHEN 1 THEN '処理中'
        WHEN 2 THEN '完了'
        ELSE '不明'
    END AS status_text
FROM orders;

基本構文(検索CASE式)

より複雑な条件を指定できます。

CASE
    WHEN 条件1 THEN 結果1
    WHEN 条件2 THEN 結果2
    WHEN 条件3 THEN 結果3
    ELSE デフォルト結果
END

使用例

SELECT 
    name,
    score,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        WHEN score >= 60 THEN 'D'
        ELSE 'F'
    END AS grade
FROM students;

単純CASE式と検索CASE式の違い

種類特徴使いどころ
単純CASE式1つの列の値で分岐ステータスコードの変換など
検索CASE式複雑な条件式で分岐範囲判定、複数列の条件など

検索CASE式の方が柔軟性が高く、よく使われます。

実践的な使用例

CASE式の具体的な活用方法を見ていきましょう。

例1:ステータス表示の変換

数値コードを分かりやすいテキストに変換します。

SELECT 
    order_id,
    customer_name,
    CASE order_status
        WHEN 0 THEN '注文受付'
        WHEN 1 THEN '準備中'
        WHEN 2 THEN '発送済み'
        WHEN 3 THEN '配達完了'
        WHEN 9 THEN 'キャンセル'
        ELSE '状態不明'
    END AS status_display
FROM orders;

例2:年齢層の分類

年齢を基に、年齢層を分類します。

SELECT 
    name,
    age,
    CASE
        WHEN age < 20 THEN '10代'
        WHEN age < 30 THEN '20代'
        WHEN age < 40 THEN '30代'
        WHEN age < 50 THEN '40代'
        WHEN age < 60 THEN '50代'
        ELSE '60代以上'
    END AS age_group
FROM customers;

例3:価格帯の表示

商品価格を基に、価格帯を表示します。

SELECT 
    product_name,
    price,
    CASE
        WHEN price < 1000 THEN '低価格帯'
        WHEN price < 5000 THEN '中価格帯'
        WHEN price < 10000 THEN '高価格帯'
        ELSE 'プレミアム'
    END AS price_range
FROM products;

例4:複数条件の組み合わせ

複数の列を使った条件分岐です。

SELECT 
    name,
    score,
    attendance_rate,
    CASE
        WHEN score >= 80 AND attendance_rate >= 90 THEN '優秀'
        WHEN score >= 60 AND attendance_rate >= 80 THEN '良好'
        WHEN score >= 60 THEN '合格'
        ELSE '不合格'
    END AS evaluation
FROM students;

例5:NULL値の処理

NULL値を特定の値に置き換えます。

SELECT 
    product_name,
    CASE
        WHEN stock_quantity IS NULL THEN '在庫情報なし'
        WHEN stock_quantity = 0 THEN '在庫切れ'
        WHEN stock_quantity < 10 THEN '残りわずか'
        ELSE '在庫あり'
    END AS stock_status
FROM products;

SELECT句での使用

CASE式は、SELECT句で最もよく使われます。

カラムの値を変換

SELECT 
    employee_id,
    name,
    CASE gender
        WHEN 'M' THEN '男性'
        WHEN 'F' THEN '女性'
        ELSE '不明'
    END AS gender_display
FROM employees;

計算結果に基づく分類

SELECT 
    product_name,
    price,
    cost,
    price - cost AS profit,
    CASE
        WHEN (price - cost) > 1000 THEN '高収益'
        WHEN (price - cost) > 0 THEN '通常'
        ELSE '赤字'
    END AS profit_status
FROM products;

複数のCASE式を併用

SELECT 
    name,
    CASE
        WHEN age < 20 THEN '若年層'
        WHEN age < 60 THEN '中年層'
        ELSE '高齢層'
    END AS age_category,
    CASE
        WHEN income < 3000000 THEN '低所得'
        WHEN income < 6000000 THEN '中所得'
        ELSE '高所得'
    END AS income_category
FROM customers;

WHERE句での使用

CASE式は、WHERE句でも使えます。

条件付きフィルタリング

-- 曜日によって異なる条件で検索
SELECT *
FROM sales
WHERE CASE DAYOFWEEK(sale_date)
    WHEN 1 THEN amount >= 10000  -- 日曜日
    WHEN 7 THEN amount >= 10000  -- 土曜日
    ELSE amount >= 5000          -- 平日
END;

動的な条件

-- 商品カテゴリによって異なる在庫基準
SELECT *
FROM products
WHERE stock_quantity < 
    CASE category
        WHEN 'A' THEN 100  -- カテゴリAは100未満
        WHEN 'B' THEN 50   -- カテゴリBは50未満
        ELSE 20            -- その他は20未満
    END;

ORDER BY句での使用

並び順をカスタマイズできます。

優先度に基づいた並び替え

SELECT *
FROM tasks
ORDER BY 
    CASE priority
        WHEN 'urgent' THEN 1
        WHEN 'high' THEN 2
        WHEN 'medium' THEN 3
        WHEN 'low' THEN 4
        ELSE 5
    END,
    due_date;

条件付きソート

-- 在庫状況で並び順を変える
SELECT *
FROM products
ORDER BY 
    CASE
        WHEN stock_quantity = 0 THEN 1      -- 在庫切れを最初に
        WHEN stock_quantity < 10 THEN 2     -- 在庫少を次に
        ELSE 3                              -- その他を最後に
    END,
    product_name;

UPDATE文での使用

既存データを条件に応じて更新できます。

条件付き値の更新

-- 価格を在庫状況に応じて調整
UPDATE products
SET price = CASE
    WHEN stock_quantity = 0 THEN price * 1.2    -- 在庫切れは20%値上げ
    WHEN stock_quantity < 10 THEN price * 1.1   -- 在庫少は10%値上げ
    WHEN stock_quantity > 100 THEN price * 0.9  -- 過剰在庫は10%値下げ
    ELSE price
END;

複数列の一括更新

-- 評価に基づいて給与とボーナスを調整
UPDATE employees
SET 
    salary = CASE
        WHEN evaluation = 'A' THEN salary * 1.1
        WHEN evaluation = 'B' THEN salary * 1.05
        ELSE salary
    END,
    bonus = CASE
        WHEN evaluation = 'A' THEN 500000
        WHEN evaluation = 'B' THEN 300000
        WHEN evaluation = 'C' THEN 100000
        ELSE 0
    END
WHERE department = 'Sales';

データベース別の条件分岐関数

CASE式以外にも、データベースごとに便利な関数があります。

MySQL の IF 関数

シンプルな2値選択に便利です。

-- IF(条件, 真の場合, 偽の場合)
SELECT 
    name,
    IF(score >= 60, '合格', '不合格') AS result
FROM students;

CASE式と比較

-- CASE式での同等表現
SELECT 
    name,
    CASE WHEN score >= 60 THEN '合格' ELSE '不合格' END AS result
FROM students;

IF関数の方が簡潔ですが、3つ以上の分岐にはCASE式が必要です。

SQL Server の IIF 関数

SQL Server 2012以降で使えます。

-- IIF(条件, 真の場合, 偽の場合)
SELECT 
    name,
    IIF(age >= 18, '成人', '未成年') AS age_category
FROM users;

COALESCE 関数

NULL値を処理するための関数です。全データベースで使用できます。

-- 最初の非NULL値を返す
SELECT 
    name,
    COALESCE(nickname, real_name, '名前なし') AS display_name
FROM users;

CASE式での同等表現

SELECT 
    name,
    CASE
        WHEN nickname IS NOT NULL THEN nickname
        WHEN real_name IS NOT NULL THEN real_name
        ELSE '名前なし'
    END AS display_name
FROM users;

NULLIF 関数

2つの値が等しい場合にNULLを返します。

-- NULLIF(値1, 値2)
SELECT 
    name,
    NULLIF(phone, '') AS phone  -- 空文字をNULLに変換
FROM customers;

使用例:ゼロ除算の回避

SELECT 
    total_sales / NULLIF(order_count, 0) AS average_sale
FROM sales_summary;
-- order_countが0の場合、NULLになるのでエラーを回避

ネストしたCASE式

CASE式の中にさらにCASE式を入れることができます。

基本的なネスト

SELECT 
    name,
    CASE gender
        WHEN 'M' THEN 
            CASE
                WHEN age < 20 THEN '男性・未成年'
                ELSE '男性・成人'
            END
        WHEN 'F' THEN 
            CASE
                WHEN age < 20 THEN '女性・未成年'
                ELSE '女性・成人'
            END
        ELSE '不明'
    END AS category
FROM users;

複雑な分類

SELECT 
    product_name,
    CASE category
        WHEN 'Electronics' THEN
            CASE
                WHEN price > 100000 THEN 'Premium Electronics'
                WHEN price > 50000 THEN 'Standard Electronics'
                ELSE 'Budget Electronics'
            END
        WHEN 'Clothing' THEN
            CASE
                WHEN price > 20000 THEN 'Luxury Clothing'
                WHEN price > 10000 THEN 'Standard Clothing'
                ELSE 'Budget Clothing'
            END
        ELSE 'Other Products'
    END AS product_classification
FROM products;

注意点

ネストが深くなると、可読性が低下します。

可能なら、AND/OR条件で表現できないか検討しましょう。

-- ネストの代わりにAND条件を使う(推奨)
SELECT 
    name,
    CASE
        WHEN gender = 'M' AND age < 20 THEN '男性・未成年'
        WHEN gender = 'M' AND age >= 20 THEN '男性・成人'
        WHEN gender = 'F' AND age < 20 THEN '女性・未成年'
        WHEN gender = 'F' AND age >= 20 THEN '女性・成人'
        ELSE '不明'
    END AS category
FROM users;

パフォーマンスへの影響

CASE式の使い方によっては、パフォーマンスに影響することがあります。

インデックスが効かないケース

WHERE句でCASE式を使うと、インデックスが効かないことがあります。

遅い例

-- カラムを加工しているため、インデックスが使えない
SELECT *
FROM products
WHERE CASE category
    WHEN 'A' THEN price > 1000
    WHEN 'B' THEN price > 2000
    ELSE FALSE
END;

改善例

-- 条件を分解してインデックスを活用
SELECT *
FROM products
WHERE (category = 'A' AND price > 1000)
   OR (category = 'B' AND price > 2000);

評価の順序

CASE式は、条件を上から順番に評価します。

最も頻繁にマッチする条件を先に書くと、効率的です。

-- 頻度の高い条件を先に
SELECT 
    CASE status
        WHEN 1 THEN '処理中'        -- 最も多い
        WHEN 2 THEN '完了'          -- 2番目に多い
        WHEN 0 THEN '未処理'        -- 少ない
        WHEN 9 THEN 'キャンセル'    -- 最も少ない
        ELSE '不明'
    END AS status_text
FROM orders;

複雑な計算の重複を避ける

同じ計算を複数回行わないようにしましょう。

非効率な例

SELECT 
    CASE
        WHEN (price * 1.1 - cost) > 1000 THEN '高収益'
        WHEN (price * 1.1 - cost) > 0 THEN '通常'
        ELSE '赤字'
    END
FROM products;
-- (price * 1.1 - cost) が複数回計算される

改善例

SELECT 
    CASE
        WHEN profit > 1000 THEN '高収益'
        WHEN profit > 0 THEN '通常'
        ELSE '赤字'
    END
FROM (
    SELECT price * 1.1 - cost AS profit
    FROM products
) AS subquery;
-- 計算は1回だけ

ベストプラクティス

CASE式を効果的に使うためのポイントです。

ELSE句を必ず含める

ELSE句がないと、条件に合わない場合にNULLが返されます。

-- 良い例:ELSE句がある
CASE status
    WHEN 0 THEN '未処理'
    WHEN 1 THEN '処理中'
    WHEN 2 THEN '完了'
    ELSE '不明'  -- 予期しない値への対応
END

-- 悪い例:ELSE句がない
CASE status
    WHEN 0 THEN '未処理'
    WHEN 1 THEN '処理中'
    WHEN 2 THEN '完了'
    -- 他の値の場合はNULL
END

可読性を重視する

複雑なCASE式は、適切にインデントして読みやすくしましょう。

SELECT 
    name,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        WHEN score >= 60 THEN 'D'
        ELSE 'F'
    END AS grade
FROM students;

データ型の一致

すべてのTHEN句とELSE句は、同じデータ型を返すようにしましょう。

-- 良い例:すべて文字列
CASE
    WHEN score >= 60 THEN '合格'
    ELSE '不合格'
END

-- 悪い例:データ型が混在
CASE
    WHEN score >= 60 THEN '合格'
    ELSE 0  -- 数値(型変換が必要になる)
END

複雑すぎる場合は別の方法を検討

CASE式が複雑になりすぎたら、以下を検討しましょう。

  • ビューを作成して段階的に処理
  • マスターテーブルを使ってJOIN
  • アプリケーション側で処理

よくある間違いと対処法

CASE式を使う際の注意点です。

間違い1:WHENとTHENの混同

-- 間違い
CASE
    WHEN score >= 60 WHEN '合格'  -- WHENが2つ
    ELSE '不合格'
END

-- 正しい
CASE
    WHEN score >= 60 THEN '合格'
    ELSE '不合格'
END

間違い2:ENDの忘れ

-- 間違い
SELECT 
    CASE status
        WHEN 0 THEN '未処理'
        WHEN 1 THEN '処理中'
        ELSE '完了'
    -- ENDがない
FROM orders;

-- 正しい
SELECT 
    CASE status
        WHEN 0 THEN '未処理'
        WHEN 1 THEN '処理中'
        ELSE '完了'
    END AS status_text
FROM orders;

間違い3:カンマの位置

-- 間違い
SELECT 
    name
    CASE status  -- カンマがない
        WHEN 0 THEN '未処理'
    END
FROM orders;

-- 正しい
SELECT 
    name,  -- カンマが必要
    CASE status
        WHEN 0 THEN '未処理'
    END AS status_text
FROM orders;

まとめ

SQLの条件分岐について解説してきました。

重要なポイント

  • SQLには厳密な「3項演算子」はないが、CASE式で同等の機能を実現できる
  • CASE式には単純CASE式と検索CASE式の2種類がある
  • SELECT、WHERE、ORDER BY、UPDATE文など様々な場所で使える
  • MySQLのIF関数、SQL ServerのIIF関数など、データベース固有の関数もある
  • COALESCE関数でNULL値を処理できる
  • ELSE句は必ず含めるべき
  • ネストは可読性を考慮して使う
  • パフォーマンスに影響することがあるので注意が必要

CASE式を使いこなせば、SQLでの条件分岐が柔軟に表現できるようになります。

まずは単純な条件から始めて、徐々に複雑な条件分岐にも挑戦してみてください。

データベースでの柔軟なデータ処理を実現していきましょう!

コメント

タイトルとURLをコピーしました