SQLのCASE式をざっくりと理解する

SQLのCASE式は便利です。しかし、どこが便利なのかよく分からなかったので、ざっくりとまとめてみました。

# CASE式のサンプル

## 対象テーブル

都道府県別の人口テーブルを対象にします。

pref_name|population|
---------|----------|
佐賀       |       100|
徳島       |       100|
愛媛       |       150|
東京       |       400|
福岡       |       300|
群馬       |       500|
長崎       |       200|
香川       |       200|
高知       |       200|

## 欲しい結果

九州、四国、その他、という３つのラベルを作り、作ったラベルごとに人口を集計します。

district|sum(population)|
--------|---------------|
九州      |            600|
四国      |            650|
その他     |            900|

## 実行SQL

```sql
select
  case pref_name
    when '徳島' then '四国'
    when '香川' then '四国'
    when '愛媛' then '四国'
    when '高知' then '四国'
    when '福岡' then '九州'
    when '佐賀' then '九州'
    when '長崎' then '九州'
    else 'その他' end as district, -- district means parts of nation
  sum(population)
from poptbl
group by district
;
```

### CASE式でやっていることのイメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34636/e2ad8938-b87e-d9e4-48b1-7ba81d6f0dc3.png)

つまり、CASE式がやっていることは、データのラベルを読みかえることだと言えます。
こちらを踏まえて、いくつか具体例を見ていきましょう。

# 例２．データを横持ちにして集計する

## やりたいこと

今度は、性別の列を設けて、都道府県別の性別ごとの人口を表現するテーブルにしました。
sex .. 1 が男、sex .. 2が女を指します。

pref_name|sex|population|
---------|---|----------|
佐賀       |1  |        20|
佐賀       |2  |        80|
徳島       |1  |        60|
徳島       |2  |        40|
愛媛       |1  |       100|
愛媛       |2  |        50|
東京       |1  |       210|
東京       |2  |       190|
福岡       |1  |       100|
福岡       |2  |       200|
群馬       |1  |       240|
群馬       |2  |       260|
長崎       |1  |       150|
長崎       |2  |        50|
香川       |1  |       100|
香川       |2  |       100|
高知       |1  |       100|
高知       |2  |       100|

こちらのテーブルから、さきほど作った新しい集合を、男女別に適用してみましょう。

## 結果のイメージ

徳島、香川、愛媛、高知を比較用に新しく用意しました。
その他と九州を削り、四国と、total（すべて）を追加しました。

sex|tokushima|kagawa|ehime|kochi|shikoku|total|
---|---------|------|-----|-----|-------|-----|
男  |       60|   100|  100|  100|    360| 1080|
女  |       40|   100|   50|  100|    290| 1070|

## 実行SQL

```sql
select
  case when sex = '1' then '男' else '女' end as sex,
  sum(case when pref_name = '徳島' then population else 0 end) as tokushima,
  sum(case when pref_name = '香川' then population else 0 end) as kagawa,
  sum(case when pref_name = '愛媛' then population else 0 end) as ehime,
  sum(case when pref_name = '高知' then population else 0 end) as kochi,
  sum(case when pref_name in ('徳島', '香川', '愛媛', '高知') then population else 0 end) as shikoku,
  sum(population) as total
from
  poptbl2
group by sex;
```

### SQLのポイント

in句を使って、四国に読みかえるデータをまとめて記述しています。

```sql
  sum(case when pref_name in ('徳島', '香川', '愛媛', '高知') then population else 0 end) as shikoku,
```

また、すべて(total)については、条件式が不要なので、pref_nameをすべて集計しています。

```sql
  sum(population) as total
```

こうしてみると、CASE式というのは、ExcelのVLookupに何となく似ているように思えます。

### SQLのイメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34636/dce9e0ab-d19a-4f22-2081-969116eb2e52.png)


# 例３．任意のソート順を実現する

データのラベルを読みかえる、というCASE式の特徴をよく現したのがこの方法だと思います。

## やりたいこと

人事評価のランキングテーブルを作りました。データの中身に、そこまで意味はありません。
こちらのデータのidの順番を、任意の値に変更してみましょう 🍌

id|num|
---------|---|
A |  1|
A |  2|
A |  3|
B |  1|
N |  1|
N |  2|

## 結果のイメージ

任意の値に変わりましたね 🍌🍌🍌

id|num|
---------|---|
B |  1|
A |  1|
N |  1|
A |  2|
N |  2|
A |  3|

## 実行SQL

```sql
select
  id,
  num
from
  ranks
order by
  case
    when id = 'B' and num = 1 then 1
    when id = 'A' and num = 1 then 2
    when id = 'N' and num = 1 then 3
    when id = 'A' and num = 2 then 4
    when id = 'N' and num = 2 then 5
    when id = 'A' and num = 3 then 6
    else null end
;
```

### SQLのポイント

order by にCASE式を導入していることがポイントです。then の後の数字を付けることで、**レコードをラベルとして読み替えているのです。**

```sql 
order by
  case
    when id = 'B' and num = 1 then 1
```

order by は、読み替えられたデータの順番でなされます。

### SQLのイメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34636/f5c49e0a-312f-7251-0b25-6f3884468149.png)

# おわりに - CASE式は何が便利か - 

CASE式について、何が便利なのかを「ラベルの読み替え」という観点から見てみました。ラベルを読みかえると、既存のデータに独自のフラグを立てることが可能となり、立てたフラグの単位で集合演算を行えます。CASE式は、この点が便利だとわかりました。

なお、CASE式は、構文によってうまく動かないことがあるとのことです。ですので、構文を検証する記事も書きました。もし宜しければ、併せてご覧ください。

https://qiita.com/omokawa_yasu/items/ca5ef00583572dc7069a