아마 이미 프로그래밍 언어에서 조건문을 써본 적 있을 거야: if-else, switch-case 같은 거 말이지. SQL에도 조건 처리용 도구가 있어: 바로 CASE 표현식! 이걸로 쿼리 안에서 바로 "조건이 맞으면 이렇게, 아니면 저렇게"를 할 수 있어.
CASE 구문은 특히 NULL 값이 들어올 수 있는 데이터를 다룰 때 진짜 유용해. 문법도 엄청 간단해서, 그냥 치트키 느낌이야. 한 번 볼까?
CASE
WHEN 조건1 THEN 결과1
WHEN 조건2 THEN 결과2
...
ELSE 기본_결과
END
딱 봐도 이해되지? "이럴 땐 이렇게, 아니면 저렇게". 외우기도 쉬워: "WHEN은 만약, THEN은 뭐 할지, ELSE는 아무것도 안 맞으면 뭐 할지".
예시: 상품 분류하기
예를 들어 products 테이블에 price 컬럼이 있고, 가격에 따라 상품을 그룹으로 나누고 싶다고 해보자.
| id | name | price |
|---|---|---|
| 1 | Magic Wand | 120 |
| 2 | Potion Set | 45 |
| 3 | Crystal Ball | 75 |
| 4 | Enchanted Map | NULL |
| 5 | Broomstick | 99 |
| 6 | Spell Book | 180 |
SELECT
name AS product_name,
price,
CASE
WHEN price IS NULL THEN '알 수 없음'
WHEN price < 50 THEN '저가'
WHEN price BETWEEN 50 AND 100 THEN '표준'
ELSE '프리미엄'
END AS price_category
FROM products;
여기서 뭐가 일어나냐면?
- 상품의
price가NULL이면 카테고리를'알 수 없음'으로 표시해. - 가격이 50 미만이면
'저가'로 분류해. - 가격이 50~100 사이면
'표준'카테고리로 들어가. - 나머지는 다
'프리미엄'상품이야.
결과는 이래:
| product_name | price | price_category |
|---|---|---|
| Magic Wand | 120 | 프리미엄 |
| Potion Set | 45 | 저가 |
| Crystal Ball | 75 | 표준 |
| Enchanted Map | NULL | 알 수 없음 |
| Broomstick | 99 | 표준 |
| Spell Book | 180 | 프리미엄 |
SQL은 마치 마법사처럼 products 테이블의 각 행을 읽고, 똑똑하게 분류해줘.
CASE WHEN에서 NULL 다루기
데이터에 빠진 값(NULL)이 자주 있는데, 이걸 뭔가로 바꿔줘야 할 때가 많아. 예를 들어 users 테이블에 email 컬럼이 있는데, 이메일 없는 유저는 '입력 안 됨'으로 표시하고 싶다고 해보자.
| user_id | name | |
|---|---|---|
| 1 | Alex Lin | alex@example.com |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | anna@magic.com |
| 4 | Otto Art | NULL |
| 5 | John Smith | john@wizard.org |
SELECT
user_id,
name,
CASE
WHEN email IS NULL THEN '입력 안 됨'
ELSE email
END AS email_address
FROM users;
| user_id | name | email_address |
|---|---|---|
| 1 | Alex Lin | alex@example.com |
| 2 | Maria Chi | 입력 안 됨 |
| 3 | Anna Song | anna@magic.com |
| 4 | Otto Art | 입력 안 됨 |
| 5 | John Smith | john@wizard.org |
SQL이 여기선 샤먼처럼 빈 칸을 채워줘. 이메일이 없으면 '입력 안 됨'으로 바꿔주고, 있으면 그대로 둬.
숫자와 함께 쓰는 조건식
가끔은 값만 바꾸는 게 아니라, 새로운 로직을 만들어야 할 때도 있어. 예를 들어 students 테이블에 score(점수)와 name 컬럼이 있다고 해보자.
| name | score |
|---|---|
| Alex Lin | 95 |
| Maria Chi | 82 |
| Anna Song | 48 |
| Otto Art | NULL |
| John Smith | 67 |
| Zoe Black | 30 |
학생들을 "우수", "통과", "실패"로 점수에 따라 평가하고 싶어.
SELECT
name AS student_name,
score,
CASE
WHEN score IS NULL THEN '점수 없음'
WHEN score >= 90 THEN '우수'
WHEN score >= 50 THEN '통과'
ELSE '실패'
END AS performance_category
FROM students;
| student_name | score | performance_category |
|---|---|---|
| Alex Lin | 95 | 우수 |
| Maria Chi | 82 | 통과 |
| Anna Song | 48 | 실패 |
| Otto Art | NULL | 점수 없음 |
| John Smith | 67 | 통과 |
| Zoe Black | 30 | 실패 |
SQL이 학생들을 엄격한 시험관처럼 분류해줘: 90점 이상은 "우수", 50점 이상은 "통과". 점수가 부족하면... 뭐, 알지?
그룹핑과 NULL 처리
데이터 그룹핑도 CASE WHEN이 빛을 발하는 분야야. 예를 들어 orders 테이블에서 상태별로 주문 개수를 세고 싶은데, NULL 상태도 포함해야 해.
| order_id | status |
|---|---|
| 1 | Completed |
| 2 | Pending |
| 3 | NULL |
| 4 | Shipped |
| 5 | Completed |
| 6 | NULL |
| 7 | Pending |
| 8 | Completed |
| 9 | Shipped |
| 10 | NULL |
SELECT
CASE
WHEN status IS NULL THEN '상태 없음'
ELSE status
END AS order_status,
COUNT(*)
FROM orders
GROUP BY
CASE
WHEN status IS NULL THEN '상태 없음'
ELSE status
END;
이 쿼리는 NULL 상태를 '상태 없음'으로 바꿔주고, 각 그룹별 주문 개수를 세어줘. 결과는 이래:
| order_status | count |
|---|---|
| Completed | 3 |
| Pending | 2 |
| Shipped | 2 |
| 상태 없음 | 3 |
실전 케이스: CASE WHEN "마술"
예시 1: NULL 고려한 정렬
가끔 NULL 값을 정렬할 때 맨 앞이나 맨 뒤로 보내고 싶을 때가 있어. 예를 들어, 우선순위가 있는 작업은 위에, 우선순위 없는(NULL) 작업은 아래에 표시하고 싶을 때 자주 써.
| task_id | task_name | priority |
|---|---|---|
| 1 | Fix bugs | 1 |
| 2 | Update documentation | 3 |
| 3 | Plan sprint | NULL |
| 4 | Code review | 2 |
| 5 | Organize meeting | NULL |
| 6 | Deploy release | 1 |
SELECT
task_name,
priority,
CASE
WHEN priority IS NULL THEN 1
ELSE 0
END AS priority_sort
FROM tasks
ORDER BY priority_sort ASC, priority ASC;
여기선 "가상" 컬럼 priority_sort를 만들어서 NULL 값은 아래로, 나머지는 오름차순 정렬해.
| task_name | priority | priority_sort |
|---|---|---|
| Deploy release | 1 | 0 |
| Fix bugs | 1 | 0 |
| Code review | 2 | 0 |
| Update documentation | 3 | 0 |
| Plan sprint | NULL | 1 |
| Organize meeting | NULL | 1 |
예시 2: NULL 고려한 계산
이번엔 orders 테이블에서 주문 총액을 계산하는데, discount 컬럼이 NULL일 수도 있어.
| order_id | total_price | discount |
|---|---|---|
| 101 | 100 | 10 |
| 102 | 200 | NULL |
| 103 | 150 | 15 |
| 104 | 120 | NULL |
| 105 | 80 | 5 |
계산이 깨지지 않게 NULL을 0으로 바꿔야 해.
SELECT
order_id,
total_price,
discount,
total_price -
CASE
WHEN discount IS NULL THEN 0
ELSE discount
END AS final_price
FROM orders;
| order_id | total_price | discount | final_price |
|---|---|---|---|
| 101 | 100 | 10 | 90 |
| 102 | 200 | NULL | 200 |
| 103 | 150 | 15 | 135 |
| 104 | 120 | NULL | 120 |
| 105 | 80 | 5 | 75 |
이 CASE 마법 덕분에 NULL이 수식 망치는 일은 없어.
orderid = 101: discount = 10. finalprice = 100 - 10 = 90. orderid = 102: discount = NULL. CASE는 0을 반환. finalprice = 200 - 0 = 200. orderid = 103: discount = 15. finalprice = 150 - 15 = 135. orderid = 104: discount = NULL. CASE는 0을 반환. finalprice = 120 - 0 = 120. orderid = 105: discount = 5. finalprice = 80 - 5 = 75.
예시 3: 사용자 상태 표시하기
실무에서 자주 만나는 게 사용자 상태(예: "활성", "대기")를 보여주거나, 데이터가 없음을 표시하는 거야. 예를 들어 users 테이블에 last_login 컬럼이 있고, 마지막 로그인 날짜가 저장돼 있다고 해보자.
| user_id | name | last_login |
|---|---|---|
| 1 | Alex Lin | 2024-12-10 |
| 2 | Maria Chi | 2025-04-20 |
| 3 | Anna Song | NULL |
| 4 | Otto Art | 2025-05-01 |
| 5 | Liam Park | 2025-05-25 |
SELECT
user_id,
name,
CASE
WHEN last_login IS NULL THEN '로그인 기록 없음'
WHEN last_login < CURRENT_DATE - INTERVAL '30 days' THEN '비활성'
ELSE '활성'
END AS user_status
FROM users;
이 쿼리로 관리 시스템이 살아나: 로그인 기록 없는 유저는 "로그인 기록 없음", 오래 안 들어온 유저는 "비활성", 나머지는 "활성"!
| user_id | name | user_status |
|---|---|---|
| 1 | Alex Lin | 비활성 |
| 2 | Maria Chi | 비활성 |
| 3 | Anna Song | 로그인 기록 없음 |
| 4 | Otto Art | 비활성 |
| 5 | Liam Park | 활성 |
자주 하는 실수와 예방법
ELSE 빼먹기: ELSE를 안 쓰면, 조건이 하나도 안 맞을 때 SQL은 그냥 NULL을 반환해. 이게 원하는 결과가 아닐 수도 있으니까, 웬만하면 ELSE를 꼭 써주는 게 좋아.
CASE
WHEN condition THEN result
-- ELSE '기본값' -- 잊지 마!
END
괄호 없는 복잡한 조건: AND, OR, NOT 등 복잡한 조건이 여러 개면 항상 괄호를 써. 안 그러면 쿼리가 "생각"을 잘못할 수도 있어.
CASE
WHEN (column1 IS NOT NULL AND column2 > 5) THEN '유효'
ELSE '무효'
END
NULL 다루기: NULL은 절대 (=)로 비교하면 안 돼. 예를 들어:
CASE
WHEN column = NULL THEN '아님!' -- 에러!
WHEN column IS NULL THEN '정답!' -- 이게 맞아.
END
GO TO FULL VERSION