単純CASE式と検索CASE式

CASE式みたいな処理って、自分の場合はこれまでアプリケーション内で行うことが多くてMySQLで行うことが少なかったです。
しかし、使う機会があって若干はまったので、備忘録として残します。

やりたかったことは、「NULLか空文字だったら値を0として取得する」ことでした。
CASE式には単純CASE式と検索CASE式があってそれが頭に入っておらず、はまっておりました。

サンプルテーブルを以下に用意します。

START TRANSACTION;
    CREATE TABLE member (
        id int(11) NOT NULL,
        name varchar(64) NOT NULL,
        gender enum('male','female') NOT NULL,
        age int(11) NOT NULL,
        memo mediumtext,
        created datetime NOT NULL,
        updated timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    ALTER TABLE member
        ADD PRIMARY KEY (id),
        ADD KEY gender (gender),
        ADD KEY age (age);

    ALTER TABLE member
        MODIFY id int(11) NOT NULL AUTO_INCREMENT;

    INSERT INTO member (name, gender, age, memo, created) VALUES
        ('suzuki', 'male', 25, 'イケメン', '2021-04-01 00:00:00'),
        ('ohtani', 'female', 30, NULL, '2021-05-01 00:00:00'),
        ('sato', 'female', 35, '', '2021-06-01 00:00:00'),
        ('nakamura', 'female', 40, 'おもしろい', '2021-07-01 00:00:00'),
        ('tanaka', 'female', 45, NULL, '2021-08-01 00:00:00'),
        ('inoue', 'male', 50, '博識', '2021-09-01 00:00:00'),
        ('ishida', 'female', 55, '優しい', '2021-10-01 00:00:00'),
        ('matsumoto',  'male', 60, '穏やか', '2021-11-01 00:00:00'),
        ('sasaki', 'male', 65, '', '2021-12-01 00:00:00'),
        ('kato', 'female', 70, '', '2022-01-01 00:00:00');
COMMIT;

テーブルの中身はざっとこんな感じ。

idnamegenderagememocreatedupdated
1suzukimale25イケメン2021-04-01 00:00:002022-05-13 14:18:42
2ohtanifemale30NULL2021-05-01 00:00:002022-05-13 14:18:42
3satofemale352021-06-01 00:00:002022-05-13 14:18:42
4nakamurafemale40おもしろい2021-07-01 00:00:00 2022-05-13 14:18:42
5tanakafemale45NULL2021-08-01 00:00:002022-05-13 14:18:42
6inouemale50博識2021-09-01 00:00:00 2022-05-13 14:18:42
7ishidafemale55優しい2021-10-01 00:00:002022-05-13 14:18:42
8matsumotomale60穏やか2021-11-01 00:00:002022-05-13 14:18:42
9sasakimale652021-12-01 00:00:002022-05-13 14:18:42
10katofemale702022-01-01 00:00:002022-05-13 14:18:42

性別が英語で入っているので日本語で取得してみたいと思います。
比較しやすいように名前と英語での性別も取得します。
以下のようにCASEのすぐ後ろにカラム名が来て、そのWHENの値と同値のCASE式を単純CASE式と呼ぶそうです。

# 単純CASE式
SELECT
    name,
    gender,
    CASE gender
        WHEN 'male' THEN '男性'
        WHEN 'female' THEN '女性'
    END AS gender_ja
FROM member;

検索結果

namegendergender_ja
suzukimale男性
ohtanifemale女性
satofemale女性
nakamurafemale女性
tanakafemale女性
inouemale男性
ishidafemale女性
matsumotomale男性
sasakimale男性
katofemale女性

maleの場合は「男性」、femaleの場合は「女性」と表示されます。

次は
60歳以上であれば「senior」
40歳以上60歳未満であれば「middle-age」
40歳未満を「young」
と出力するようにします。

検索CASE式ではWHENの後に検索条件が入ります。
CASEの後に列名は必要ありません。

# 検索CASE式
SELECT
    name,
    age,
    CASE 
        WHEN age >= 60 THEN 'senior'
        WHEN age >= 40 && age < 60 THEN 'middle-age'
        ELSE 'young'
    END AS generation
FROM member;

検索結果

nameagegeneration
suzuki25young
ohtani30young
sato35young
nakamura40middle-age
tanaka45middle-age
inoue50middle-age
ishida55middle-age
matsumoto60senior
sasaki65senior
kato70senior

応用が効くのは検索CASE式で単純CASE式は、検索CASE式でも行うことが出来ます。

最初に行った性別を日本語で表示する単純CASE式を検索CASE式で書いてみます。

# 検索CASE式
# 結果は二つ上の表と同じ
SELECT
    name,
    gender,
    CASE
        WHEN gender LIKE 'male' THEN '男性'
        WHEN gender LIKE 'female' THEN '女性'
    END AS gender_ja
FROM member;

今回やりたかったことは、「NULLか空文字だったら値を0として取得する」だったので、検索CASE式を使えば簡単に出来そうです。
CASEの後ろに memo と書いていたので若干はまっていました。

SELECT
    name,
    memo,
    CASE
        WHEN (memo IS NULL || memo = '') THEN 0
        ELSE 1
    END AS memo_exists
FROM member;

検索結果

namememomemo_exists
suzukiイケメン1
ohtaniNULL0
sato0
nakamuraおもしろい1
tanakaNULL0
inoue博識1
ishida優しい1
matsumoto穏やか1
sasaki0
kato0

めでたしです。
と、最初は上のSQLを書いたのですがCHAR_LENGTHを使えば空文字判定出来そうですね…。
TRIMも必要なら一緒にすれば良さそうです(全角スペースは除かれないので注意)。

SELECT
    name,
    memo,
    CASE
        WHEN CHAR_LENGTH(memo) > 0 THEN 1
        ELSE 0
    END AS memo_exists
FROM member;

上のIF文を使って書くことも可能です。

SELECT
    name,
    memo,
    IF(CHAR_LENGTH(memo) > 0, 1, 0) AS memo_exists
FROM member;

単純CASEで書けるところも検索CASE式で書けるので、検索CASE式 → 単純CASE式の順に学んだ方が覚えやすい気がします。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です