【SQL】これ以上の値上げは勘弁してください 。CASE式で正しく値上げする

# はじめに

株式会社YUZURIHAの馬場です

昨日、何気なく買ったピノが1個175円 ぐらいしたので値段間違ってる？と疑ってしまったので記事書きました

# まずは、アイスクリームテーブルを用意

```sql
CREATE TABLE ice_cream
(
  id INT NOT NULL,
  name VARCHAR(100) NOT NULL,
  type VARCHAR(32) NOT NULL,
  price INT,
  delivery_date DATE,
  PRIMARY KEY (id)
);

INSERT INTO ice_cream VALUES (1, 'BLUE SEAL' ,'ラクトアイス', 300, '2022-09-20');
INSERT INTO ice_cream VALUES (2, 'スーパーカップ' ,'ラクトアイス', 120, '202-08-01');
INSERT INTO ice_cream VALUES (3, '北極アイスキャンデー' ,'ラクトアイス', 100, '2022-09-20');
INSERT INTO ice_cream VALUES (4, 'ガリガリ君' ,'氷菓', 60, '2022-08-30');
INSERT INTO ice_cream VALUES (5, 'PARM(パルム)' ,'アイスクリーム', 150, '2022-09-20');
INSERT INTO ice_cream VALUES (6, '雪見だいふく' ,'アイスミルク', 120, '2022-09-20');
INSERT INTO ice_cream VALUES (7, 'sacre(サクレ)' ,'氷菓', 90, '2022-08-01');
```

こんな感じですねー（データはもちろん仮です）

```
postgres=# select * from ice_cream;
 id |      name      |      type      | price | delivery_date
----+----------------+----------------+-------+---------------
  1 | BLUE SEAL     | ラクトアイス      |   300 | 2022-09-20
  2 | スーパーカップ    | ラクトアイス     |   120 | 2022-08-01
  3 | 北極アイスキャンデー| ラクトアイス     |   100 | 2022-09-20
  4 | ガリガリ君       | 氷菓            |    60 | 2022-08-30
  5 | PARM(パルム)   | アイスクリーム      |   150 | 2022-09-20
  6 | 雪見だいふく     | アイスミルク       |   120 | 2022-09-20
  7 | sacre(サクレ)   | 氷菓            |    90 | 2022-08-01
(7 rows)
```

# さあ、値上げをしよう

ある日、

**・100円以上、140円未満の商品は20%の値上げ**
**・140円以上の商品は10%の値上げ**
が決定したとします

てことは、毎週買ってるスーパーカップが144円に😱

そして、泣く泣くデータを更新をすることに。。。

はいはい、簡単ですよ。単純な`UPDATE`文ですよね

最初に

```sql
update ice_cream set price = price * 1.2 where 100 <= price and price < 150;
```

を実行して、ほんで

```sql
update ice_cream set price = price * 1.1 where price >= 150;
```

はい。これで完成と。

```
（更新後）
 id |      name      |      type      | price | delivery_date
----+----------------+----------------+-------+---------------
  4 | ガリガリ君        | 氷菓           |    60 | 2022-08-30
  7 | sacre(サクレ)    | 氷菓           |    90 | 2022-08-01
  3 | 北極アイスキャンデー| ラクトアイス      |   120 | 2022-09-20    
  1 | BLUE SEAL      | ラクトアイス     |   330 | 2022-09-20
  5 | PARM(パルム)    | アイスクリーム     |   165 | 2022-09-20
  2 | スーパーカップ    | ラクトアイス       |   158 | 2022-08-01
  6 | 雪見だいふく      | アイスミルク      |   158 | 2022-09-20
```

### 🙀😱🙀😱🙀😱🙀😱🙀😱🙀😱🙀😱🙀😱🙀😱🙀😱🙀😱

スーパーカップ 158円 !?!?
スーパーカップと、雪見だいふくが２度値上げされている
大好きな`スーパーカップ チョコチップ味`はもう上級国民御用達アイスに成り上がりました

先ほどのSQLでは、
条件1と、条件2 の2つに分けてUPDATEを行なっていることが良くないです。
条件1の値上げの後に、条件2にも当てはまれば2度更新されるのも当然です

# CASE式で正しく値上げする

ここで使用するのがCASE式です。UPDATE内で1度で条件分岐で済みます。
正しくは以下のSQLですね

```sql
update ice_cream
    set price = 
        case when 100 <= price and price < 140 then price * 1.2
             when price >= 140 then price * 1.1 
             else price
        end;
```

以下が、正しく値上げされたもの

```
 id |      name      |      type      | price | delivery_date
----+----------------+----------------+-------+---------------
  1 | BLUE SEAL      | ラクトアイス      |   330 | 2022-09-20
  2 | スーパーカップ    | ラクトアイス        |   144 | 2022-08-01
  3 | 北極アイスキャンデー| ラクトアイス       |   120 | 2022-09-20
  4 | ガリガリ君       | 氷菓             |    60 | 2022-08-30
  5 | PARM(パルム)   | アイスクリーム      |   165 | 2022-09-20
  6 | 雪見だいふく      | アイスミルク      |   144 | 2022-09-20
  7 | sacre(サクレ)   | 氷菓            |    90 | 2022-08-01
```

`else price`が無いと、値段には`NULL`が出力されてしまうのでここでは必須になります。

# 最後に

値上げなんてやめて、閉店セールにでもしましょうか

```sql
update ice_cream set price = price * 0.5;
```

```
 id |      name      |      type      | price | delivery_date
----+----------------+----------------+-------+---------------
  1 | BLUE SEAL      | ラクトアイス     |   150 | 2022-09-20
  2 | スーパーカップ    | ラクトアイス       |    60 | 2022-08-01
  3 | 北極アイスキャンデー | ラクトアイス      |    50 | 2022-09-20
  4 | ガリガリ君        | 氷菓           |    30 | 2022-08-30
  5 | PARM(パルム)    | アイスクリーム     |    75 | 2022-09-20
  6 | 雪見だいふく     | アイスミルク       |    60 | 2022-09-20
  7 | sacre(サクレ)   | 氷菓            |    45 | 2022-08-01
```