# 15강. CASE 문으로 데이터 변환하기
- `CASE` 문을 이용해 데이터를 변환할 수 있다.

**`CASE 문`**
```
CASE WHEN 조건식1 THEN 식1
    [WHEN 조건식2 THEN 식2] 
    [ELSE 식3]
END
```

- 임의의 조건에 따라 독자적으로 변환 처리를 지정해 데이터로 변환하고 싶은 경우에 `CASE` 문을 이용할 수 있다.

---

## 1. CASE 문
- `RDBMS`에 갖추어져 있는 기존의 연산자나 함수만으로는 처리할 수 없는 것들이 있다.
- 예를 들면 `NULL` 값을 0으로 간주하여 계산하고 싶은 경우라던가.
- 하지만 `NULL` 값으로 계산한 결과는 모두 `NULL`이 된다.
- `RDBMS`에서는 사용자가 함수를 작성할 수 있다.
- 하지만 간단한 처리의 경우에는 사용자 정의 함수를 작성하지 않고도 `CASE` 문으로 처리할 수 있다.

**`CASE 문`**
```
CASE WHEN 조건식1 THEN 식1
    [WHEN 조건식2 THEN 식2]
    [ELSE 식3]
END
```

- 먼저 `WHEN` 절에는 참과 거짓을 반환하는 조건식을 기술한다.
- 해당 조건을 만족하여 참이 되는 경우는 `THEN` 절에 기술한 식이 처리된다.
- 이때 `WHEN`과 `THEN`을 한데 조합해 사용할 수 있다.
- `WHEN` 절의 조건식을 차례로 평가해 나가다가 가장 먼저 조건을 만족한 `WHEN` 절과 대응하는 `THEN` 절 식의 처리결과를 `CASE` 문의 결괏값으로 반환한다.
- 그 어떤 조건식도 만족하지 못한 경우에는 `ELSE` 절에 기술한 식이 채택된다.
- `ELSE`는 생략 가능하며 생략했을 경우 `ELSE NULL`로 간주된다.

**`CASE로 NULL 값을 0으로 변환하기`**
```
SELECT a, CASE WHEN a IS NULL THEN 0 ELSE a END "a(null=0)" FROM sample37;
```

- a 열 값이 `NULL`일 때 `WHEN a IS NULL`은 참이 되므로 `CASE` 문은 `THEN` 절의 '0'을 반환한다.
- `NULL`이 아닌 경우에는 `ELSE` 절의 'a', 즉 a 열의 값을 반환한다.

### COALESCE
- 사실 `NULL` 값을 변환하는 경우라면 `COALESCE` 함수를 사용하는 편이 더 쉽다.
- 앞의 예제에 `COALESCE` 함수를 사용해 구현하면 다음과 같다.

```
SELECT a, COALESCE(a, 0) FROM sample37;
```

- `COALESCE` 함수는 여러 개의 인수를 지정할 수 있다.
- 주어진 인수 가운데 `NULL`이 아닌 값에 대해서는 가장 먼저 지정된 인수의 값을 반환한다.
- 앞의 예문은 a가 `NULL`이 아니면 a값을 그대로 출력하고, 그렇지 않으면(a가 `NULL`이면) 0을 출력한다.

---

## 2. 또 하나의 CASE 문
- 숫자로 이루어진 코드를 알아보기 더 쉽게 문자열로 변환하고 싶은 경우 `CASE` 문을 많이 사용한다.
- 이와 같이 문자화하는 것을 `디코드`라 부르고 반대로 수치화하는 것을 `인코드`라 부른다.
- 이와 같은 인코드를 `CASE` 문으로 처리할 수 있다.

```
WHEN a = 1 THEN '남자'
WHEN a = 2 THEN '여자'
```

##### CASE 문에는 2개의 구문이 있다!

- `CASE` 문은 `검색 CASE`와 `단순 CASE`의 두 개 구문으로 나눌 수 있다.
- `검색 CASE`는 앞서 설명한 `CASE WHEN 조건식 THEN 식 ...` 구문이다.
- 한편 `단순 CASE`는 `CASE 식 WHEN 식 THEN 식 ...` 구문이다.
- `단순 CASE`에서는 `CASE` 뒤에 식을 기술하고 `WHEN` 뒤에 (조건식이 아닌) 식을 기술한다.

**`단순 CASE 식`**
```
CASE 식1
    WHEN 식2 THEN 식3
    [WHEN 식4 THEN 식5 ...]
    [ELSE 식6]
END
```

- 식1의 값이 `WHEN`의 식2의 값과 동일한지 비교하고, 값이 같다면 식3의 값이 `CASE` 문 전체의 결괏값이 된다.
- 값이 같지 않으면 그 뒤에 기술한 `WHEN` 절과 비교하는 식으로 진행된다.
- 즉, 식1의 값과 식4의 값이 같은지를 비교하고 같다면 식5의 값이 `CASE` 문의 결괏값이 되는 것이다.
- 비교 결과 일치하는 `WHEN` 절이 하나도 없는 경우에는 `ELSE` 절이 적용된다.

**`성별 코드 변환하기(검색 CASE)`**
```
SELECT a AS "코드",
CASE
    WHEN a = 1 THEN '남자'
    WHEN a = 2 THEN '여자'
    ELSE '미지정'
END AS "성별" FROM sample37;
```

- `검색 CASE`의 경우에는 `WHEN`에 `a = 1`, `a = 2`처럼 식을 상세하게 기술해야 하지만 `단순 CASE`에서는 `CASE` 문에서 비교할 항목인 'a'를 따로 지정하므로 `WHEN`에는 1, 2처럼 비교할 값만 기술하면 된다.

**`성별 코드 변환하기(단순 CASE)`**
```
SELECT a AS "코드",
CASE a
    WHEN 1 THEN '남자'
    WHEN 2 THEN '여자'
    ELSE '미지정'
END AS "성별" FROM sample37;
```

---

## 3. CASE를 사용할 경우 주의사항
- `CASE` 문은 어디에나 사용할 수 있다.
- `WHERE` 구에서 조건식의 일부로 사용될 수도 있고 `ORDER BY` 구나 `SELECT` 구에서도 사용할 수 있다.

### ELSE 생략
- `ELSE`를 생략하면 `ELSE NULL`이 되는 것에 주의해야 한다.
- 상정한 것 이외의 데이터가 들어오는 경우도 많다.
- 이때 대응하는 `WHEN`이 하나도 없으면 `ELSE` 절이 사용된다.
- 이때 `ELSE`를 생략하면 상정한 것 이외의 데이터가 왔을 때 `NULL`이 반환된다.
- 따라서 `ELSE`를 생략하지 않고 지정하는 편이 낫다.

##### CASE 문의 ELSE는 생략하지 않는 편이 낫다!

### WHEN에 NULL 지정하기
- `단순 CASE`에서는 `WHEN` 뒤에 1개의 상수값을 지정하는 경우가 많다.
- 만약 데이터가 `NULL`인 경우를 고려해 `WHEN NULL THEN '데이터 없음'`과 같이 지정해도 문법적으로는 문제가 없지만 정상적으로 처리되지 않는다.
- 비교 연산자 `=` 로는 `NULL` 값과 같은지 아닌지를 비교할 수 없다.
- 따라서 a열의 값이 `NULL`이라 해도 `a = NULL`은 참이 되지 않는다.
- 즉, '데이터 없음' 대신 '미지정'이라는 결괏값이 나온다.
- `단순 CASE` 문으로는 `NULL`을 비교할 수 없다는 문제점이 있다.
- 이때 `NULL 값인지 아닌지를 판정하기 위해서는 IS NULL을 사용`한다.
- 다만 `단순 CASE` 문은 특성상 `=` 연산자로 비교하는 만큼, `NULL` 값인지를 판정하려면 `검색 CASE` 문을 사용해야 한다.

**`검색 CASE 문으로 NULL 판정하기`**
```
CASE
    WHEN a = 1 THEN '남자'
    WHEN a = 2 THEN '여자'
    WHEN a IS NULL THEN '데이터 없음'
    ELSE '미지정'
END
```

##### 단순 CASE 문으로는 NULL 값을 비교할 수 없다!

### DECODE NVL
- `Oracle`에는 이 같은 디코드를 수행하는 `DECODE` 함수가 내장되어 있다.
- `DECODE` 함수는 `CASE` 문과 같은 용도로 사용할 수 있다.
- 다만 `DECODE` 함수는 `Oracle`에서만 지원하는 함수인 만큼 다른 데이터베이스 제품에서는 사용할 수 없다.
- 그에 비해 `CASE` 문은 표준 SQL로 규정된 덕분에 많은 데이터베이스 제품이 지원한다.
- 또한 `NULL` 값을 변환하는 함수도 있는데 `Oracle`에서는 `NVL` 함수, `SQL Server`에서는 `ISNULL` 함수가 이에 해당한다.
- 다만 이 함수들은 특정 데이터베이스에 국한된 함수인 만큼 `NULL` 값을 변환할 때는 표준 SQL로 규정되어 있는 `COALESCE` 함수를 사용하자.

---