IF() / IIF() 関数
条件によって返す値を切り替えるショートカット関数です。『MySQL』の IF(条件, 真の値, 偽の値) と『SQL Server』の IIF(条件, 真, 偽) を使うと、CASE WHEN よりも簡潔に二択の分岐を書けます。
構文
-- MySQL: 条件が真なら真の値、偽なら偽の値を返します。 SELECT IF(条件, 真の値, 偽の値); -- SQL Server: IIF は IF と同じ動作をします(SQL Server 2012以降)。 SELECT IIF(条件, 真の値, 偽の値); -- ネストした IF(可読性が下がるため CASE WHEN を推奨します)。 SELECT IF(条件1, 値1, IF(条件2, 値2, 値3));
構文一覧
| 構文 | 概要 |
|---|---|
| IF(条件, 真の値, 偽の値) | 条件が真であれば真の値を、偽であれば偽の値を返します(MySQL独自)。 |
| IIF(条件, 真の値, 偽の値) | IF と同じ動作をします(SQL Server 2012以降)。内部的に CASE WHEN に変換されます。 |
| CASE WHEN 条件 THEN 値 ELSE 値 END | 標準SQLの条件分岐式です。3つ以上の分岐や移植性が必要なときに使用します。 |
| NULLIF(値1, 値2) | 値1と値2が等しい場合にNULLを返します。IF と組み合わせてゼロ除算の回避に使えます。 |
| COALESCE(値1, 値2, ...) | 最初のNULLでない値を返します。IF によるNULL置換より可読性が高くなります。 |
サンプルコード
SQL(MySQL)
-- サンプルデータ: ドラゴンボールキャラクターの戦闘力テーブル。
-- CREATE TABLE fighters (
-- id INT PRIMARY KEY,
-- name VARCHAR(20) NOT NULL,
-- power INT, -- 戦闘力(NULLは未計測を表します)。
-- is_saiyan TINYINT(1) -- 1: サイヤ人, 0: 地球人・その他。
-- );
-- IF で戦闘力が 5000 以上かどうかを判定します。
SELECT name, power,
IF(power >= 5000, 'エリート戦士', '一般戦士') AS rank
FROM fighters;
-- IIF(SQL Serverの場合)でも同じ結果が得られます。
-- SELECT name, power,
-- IIF(power >= 5000, 'エリート戦士', '一般戦士') AS rank
-- FROM fighters;
-- IF でサイヤ人かどうかをラベル表示します。
SELECT name,
IF(is_saiyan = 1, 'サイヤ人', 'その他') AS race_label
FROM fighters;
-- NULL(未計測)を含む列には COALESCE を組み合わせます。
-- IF だけで書くと冗長になるため、COALESCE の利用を推奨します。
SELECT name,
COALESCE(power, 0) AS power_display,
IF(COALESCE(power, 0) >= 5000, 'エリート', '未確認') AS rank
FROM fighters;
-- NULLIF と IF を組み合わせてゼロ除算を回避します。
-- battles: 試合数, wins: 勝利数。
SELECT name,
IF(NULLIF(battles, 0) IS NULL,
NULL,
wins / NULLIF(battles, 0)) AS win_rate
FROM fighters;
-- ネストした IF(3段階の分岐)は可読性が下がります。
-- 3つ以上の分岐には CASE WHEN を使うことを推奨します。
SELECT name, power,
IF(power >= 8000, '超戦士',
IF(power >= 5000, 'エリート戦士',
'一般戦士')) AS rank_nested -- 読みにくいため CASE WHEN を推奨します。
FROM fighters;
-- CASE WHEN で書き直した可読性の高いバージョンです。
SELECT name, power,
CASE
WHEN power >= 8000 THEN '超戦士'
WHEN power >= 5000 THEN 'エリート戦士'
ELSE '一般戦士'
END AS rank_case
FROM fighters;
実行結果(SELECT name, power, IF(...) AS rank FROM fighters;)
-- +------------+-------+--------------+ -- | name | power | rank | -- +------------+-------+--------------+ -- | 孫悟空 | 9000 | エリート戦士 | -- | ベジータ | 8500 | エリート戦士 | -- | 孫悟飯 | 3000 | 一般戦士 | -- | ピッコロ | 3500 | 一般戦士 | -- | クリリン | 1500 | 一般戦士 | -- +------------+-------+--------------+
実行結果(SELECT name, CASE WHEN ... END AS rank_case FROM fighters;)
-- +------------+-------+--------------+ -- | name | power | rank_case | -- +------------+-------+--------------+ -- | 孫悟空 | 9000 | 超戦士 | -- | ベジータ | 8500 | 超戦士 | -- | 孫悟飯 | 3000 | 一般戦士 | -- | ピッコロ | 3500 | 一般戦士 | -- | クリリン | 1500 | 一般戦士 | -- +------------+-------+--------------+
データベース別の書き方
『IF』はMySQL独自の関数であり、標準SQLには含まれません。『IIF』はSQL Serverの独自関数(2012以降)です。移植性が必要な場合は標準SQLの『CASE WHEN』を使用してください。
-- MySQL: IF 関数を使います。
SELECT name, IF(power >= 5000, 'エリート戦士', '一般戦士') AS rank FROM fighters;
-- SQL Server: IIF 関数を使います(SQL Server 2012以降)。
SELECT name, IIF(power >= 5000, 'エリート戦士', '一般戦士') AS rank FROM fighters;
-- 標準SQL(MySQL・PostgreSQL・Oracle・SQL Server・SQLite 共通)。
SELECT name,
CASE WHEN power >= 5000 THEN 'エリート戦士' ELSE '一般戦士' END AS rank
FROM fighters;
PostgreSQL・Oracle・SQLite には IF 関数がないため、CASE WHEN を使用してください。NULL置換には標準SQLの『COALESCE』が全データベースで使用できます。
概要
『IF』と『IIF』は二択の分岐を簡潔に書けますが、MySQL と SQL Server にのみ存在する独自関数です。移植性を重視する場合や3つ以上の分岐が必要な場合は、標準SQLの『CASE WHEN』を使用してください。
ネストした IF(IF(条件1, 値1, IF(条件2, 値2, 値3)))は動作しますが、階層が深くなると非常に読みにくくなります。分岐が3段階以上になる場合は迷わず CASE WHEN に切り替えることを推奨します。
NULL 置換が目的であれば、IF(列名 IS NULL, 代替値, 列名) と書くより『COALESCE』の方が簡潔で移植性も高くなります。ゼロ除算を回避したい場合は『NULLIF』と組み合わせる方法が一般的です。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。