CASE는 SQL 쿼리에 if/then/else 로직을 더해요. 조건 목록을 차례로 확인하고, 처음으로 참이 되는 조건의 결과를 반환해요. 예제는 PostgreSQL, MySQL, SQLite, SQL Server에서 모두 동작해요.
CASE 사용법
CASE와 END 사이에 WHEN condition THEN result 쌍을 나열하세요. CASE는 처음으로 참이 되는 조건의 결과를 반환하고, 참인 조건이 없으면 ELSE 값을 반환해요:
CASE
WHEN condition THEN result
[WHEN condition THEN result ...]
[ELSE result]
END
SELECT
CASE
WHEN 72 >= 90 THEN 'Hot'
WHEN 72 >= 60 THEN 'Mild'
ELSE 'Cold'
END;
-- Output: Mild
모든 조건이 같은 값의 일치 여부만 확인한다면, 더 짧은 “단순” 형식으로 그 값을 한 번만 쓸 수 있어요:
SELECT
CASE 'amber'
WHEN 'green' THEN 'Go'
WHEN 'amber' THEN 'Slow down'
WHEN 'red' THEN 'Stop'
ELSE 'Unknown'
END;
-- Output: Slow down
실제 쿼리에서는 조건이 컬럼을 검사하고, CASE가 결과에 새 컬럼을 추가해요:
-- Input: orders
-- order_id | amount
-- ---------+--------
-- 1001 | 45.00
-- 1002 | 100.00
-- 1003 | 349.99
-- 1004 | 1250.00
SELECT
order_id,
amount,
CASE
WHEN amount < 100 THEN 'Small'
WHEN amount < 500 THEN 'Medium'
ELSE 'Large'
END AS order_size
FROM orders;
-- Output:
-- order_id | amount | order_size
-- ---------+---------+-----------
-- 1001 | 45.00 | Small
-- 1002 | 100.00 | Medium
-- 1003 | 349.99 | Medium
-- 1004 | 1250.00 | Large
알아 둘 규칙
-
처음으로 참인 조건이 이겨요. 조건은 위에서 아래로 확인되므로 가장 좁은 조건을 먼저 두세요. 위 예에서
100.00은amount < 100이 거짓이고amount < 500이 참이라서 Medium이 돼요. 순서가 잘못되면 작은 금액은 자기 분기에 절대 도달하지 못해요:
SELECT
CASE
WHEN 45 < 500 THEN 'Medium'
WHEN 45 < 100 THEN 'Small' -- can never win
ELSE 'Large'
END;
-- Output: Medium
- ELSE가 없으면 일치하지 않을 때 NULL이 돼요.
SELECT CASE WHEN 72 >= 90 THEN 'Hot' END;
-- Output: NULL
-
NULL은 IS NULL로 검사하세요.
NULL = NULL은 참이 아니므로 단순 형식으로는 NULL을 일치시킬 수 없어요. 검색 형식을 사용하세요:
SELECT CASE NULL WHEN NULL THEN 'matched' ELSE 'no match' END;
-- Output: no match
SELECT CASE WHEN NULL IS NULL THEN 'matched' ELSE 'no match' END;
-- Output: matched
- 모든 결과는 호환되는 타입이어야 해요. 하나의 CASE에 숫자와 텍스트를 섞으면 PostgreSQL과 SQL Server에서 오류가 나니, 숫자를 형변환하세요:
-- Input: products
-- name | stock
-- -------------+------
-- Desk Lamp | 12
-- Office Chair | 0
SELECT name, CASE WHEN stock > 0 THEN stock ELSE 'Sold out' END AS stock
FROM products;
-- PostgreSQL: ERROR: invalid input syntax for type integer: "Sold out"
-- SQL Server: Conversion failed when converting the varchar value 'Sold out' to data type int.
-- (in MySQL, cast with CAST(stock AS CHAR))
SELECT
name,
CASE WHEN stock > 0 THEN CAST(stock AS VARCHAR(10)) ELSE 'Sold out' END AS stock
FROM products;
-- Output:
-- name | stock
-- -------------+---------
-- Desk Lamp | 12
-- Office Chair | Sold out
다른 문법
조건이 하나뿐이라면 더 짧은 함수도 자주 볼 수 있어요:
-- MySQL
SELECT IF(72 >= 60, 'Mild', 'Cold');
-- Output: Mild
-- SQL Server and SQLite
SELECT IIF(72 >= 60, 'Mild', 'Cold');
-- Output: Mild
다른 두 함수는 자주 쓰는 CASE 식의 축약형이에요. COALESCE(nickname, name)은 CASE WHEN nickname IS NOT NULL THEN nickname ELSE name END와 같고, NULLIF(a, b)는 CASE WHEN a = b THEN NULL ELSE a END와 같아요. 앞의 함수는 SQL COALESCE 가이드를 참고하세요.
MySQL에는 저장 프로시저용 CASE 문도 있는데, END CASE로 끝나요. 이 글에서는 쿼리에서 사용하는 CASE 식을 다뤄요.
CASE는 언제 사용해야 할까요?
CASE는 식이므로 값이 올 수 있는 곳이라면 어디서든 동작해요. SELECT 목록, ORDER BY와 GROUP BY, 집계 함수 안에서도요. WHERE에서도 동작하지만, 거기서는 보통 AND와 OR만 쓰는 편이 더 명확해요. 대부분의 사용 사례는 다음 다섯 가지 중 하나에 해당해요.
숫자를 구간으로 나누기
숫자를 가격대, 주문 규모, 연령대, 등급 같은 구간으로 바꿔 보세요. 조건을 척도의 한쪽 끝에서 다른 쪽 끝 순서로 작성하면 처음 일치하는 조건이 올바른 구간이 돼요.
코드를 레이블로 바꾸기
데이터베이스는 'A', 'ENG', 'gold' 같은 짧은 코드를 저장하지만, 사람들은 단어를 원하죠. 단순 CASE는 각 코드를 레이블이나 할인율 같은 값으로 매핑하고, ELSE는 예상하지 못한 코드를 잡아내요.
일부 행만 세거나 합계 내기
COUNT나 SUM 안에 CASE를 넣으면 조건을 만족하는 행만 세거나 더할 수 있어요. COUNT(CASE WHEN ... THEN 1 END)가 동작하는 이유는 일치하지 않는 행이 NULL이 되고 COUNT가 NULL을 건너뛰기 때문이에요. 조건마다 집계를 하나씩 두면 여러 합계를 나란히 얻을 수 있는데, 이것이 SQL로 피벗 테이블을 만드는 방법이에요.
누락된 값 처리하기
선호하는 순서대로 컬럼의 NULL 여부를 확인하고, 모두 비어 있으면 레이블을 반환하세요. 단순한 대체 값이라면 COALESCE가 더 짧아요. 빈 값의 종류마다 다른 결과가 필요할 때는 CASE가 적합해요.
원하는 순서로 정렬하기
알파벳순이나 숫자순이 모든 경우에 맞지는 않아요. 옷 사이즈, 티켓 우선순위, 추천 상품을 맨 앞에 두는 목록 같은 경우죠. ORDER BY에 CASE를 쓰면 각 값을 원하는 위치에 둘 수 있어요.
CASE 실전 예제
부서와 가격으로 상품 분류하기
결과 자체가 CASE일 수도 있어서, 부서마다 고유한 가격대를 둘 수 있어요:
-- Input: products
-- product_name | category | price
-- -----------------+-------------+--------
-- Laptop Pro 14 | Electronics | 1499.00
-- Wireless Earbuds | Electronics | 129.00
-- Leather Jacket | Clothing | 349.00
-- Cotton T-Shirt | Clothing | 19.99
-- Coffee Mug | Kitchen | 12.50
SELECT
product_name,
CASE category
WHEN 'Electronics' THEN
CASE
WHEN price > 1000 THEN 'Premium Electronics'
ELSE 'Standard Electronics'
END
WHEN 'Clothing' THEN
CASE
WHEN price > 200 THEN 'Designer Clothing'
ELSE 'Regular Clothing'
END
ELSE 'Other Products'
END AS product_class
FROM products;
-- Output:
-- product_name | product_class
-- -----------------+---------------------
-- Laptop Pro 14 | Premium Electronics
-- Wireless Earbuds | Standard Electronics
-- Leather Jacket | Designer Clothing
-- Cotton T-Shirt | Regular Clothing
-- Coffee Mug | Other Products
두 단계를 넘어가면 중첩 CASE는 읽기 어려워져요. 조인하는 조회 테이블을 쓰는 편이 보통 더 명확해요.
고객 등급별 할인 적용하기
각 등급 코드는 할인율에 매핑되고, 등급이 없는 고객은 할인을 받지 않아요:
-- Input: customers
-- id | customer_name | tier
-- ---+---------------+-------
-- 1 | Maya Brooks | gold
-- 2 | Leo Martin | silver
-- 3 | Ava Kim | bronze
-- 4 | Noah Price | NULL
-- Input: orders
-- id | customer_id | order_total
-- ----+-------------+------------
-- 101 | 1 | 200.00
-- 102 | 2 | 150.00
-- 103 | 3 | 80.00
-- 104 | 4 | 60.00
SELECT
customer_name,
order_total,
ROUND(order_total * CASE tier
WHEN 'gold' THEN 0.15
WHEN 'silver' THEN 0.10
WHEN 'bronze' THEN 0.05
ELSE 0
END, 2) AS discount
FROM customers c
JOIN orders o ON c.id = o.customer_id
ORDER BY o.id;
-- Output:
-- customer_name | order_total | discount
-- --------------+-------------+---------
-- Maya Brooks | 200.00 | 30.00
-- Leo Martin | 150.00 | 15.00
-- Ava Kim | 80.00 | 4.00
-- Noah Price | 60.00 | 0.00
월별 매출을 컬럼으로 피벗하기
월마다 SUM(CASE ...)를 하나씩 쓰면 매출 행이 월별 컬럼으로 바뀌어요:
-- Input: sales
-- product_category | sale_date | amount
-- -----------------+------------+-------
-- Books | 2026-01-12 | 40.00
-- Games | 2026-01-20 | 60.00
-- Books | 2026-02-03 | 25.00
-- Books | 2026-03-15 | 30.00
-- Games | 2026-03-28 | 75.00
SELECT
product_category,
SUM(CASE WHEN EXTRACT(MONTH FROM sale_date) = 1 THEN amount ELSE 0 END) AS jan_sales,
SUM(CASE WHEN EXTRACT(MONTH FROM sale_date) = 2 THEN amount ELSE 0 END) AS feb_sales,
SUM(CASE WHEN EXTRACT(MONTH FROM sale_date) = 3 THEN amount ELSE 0 END) AS mar_sales
FROM sales
GROUP BY product_category
ORDER BY product_category;
-- Output:
-- product_category | jan_sales | feb_sales | mar_sales
-- -----------------+-----------+-----------+----------
-- Books | 40.00 | 25.00 | 30.00
-- Games | 60.00 | 0 | 75.00
SQL Server에서는 EXTRACT 대신 MONTH(sale_date) = 1을, SQLite에서는 strftime('%m', sale_date) = '01'을 사용하세요.
누락된 값과 빈 값 구분하기
가져온 데이터에는 NULL과 빈 문자열이 함께 있는 경우가 많아요. CASE로 각각에 레이블을 붙이면 무엇을 정리해야 할지 알 수 있어요:
-- Input: users
-- id | middle_name
-- ---+------------
-- 1 | Rose
-- 2 |
-- 3 | NULL
SELECT
id,
CASE
WHEN middle_name IS NULL THEN 'Missing'
WHEN middle_name = '' THEN 'Empty'
ELSE middle_name
END AS middle_name
FROM users;
-- Output:
-- id | middle_name
-- ---+------------
-- 1 | Rose
-- 2 | Empty
-- 3 | Missing
추천 상품을 맨 앞에 두기
각 카테고리에 정렬 위치를 지정한 다음, 그 안에서 이름순으로 정렬하세요:
-- Input: products
-- product_name | category
-- -------------+------------
-- Wool Scarf | Sale
-- Desk Lamp | Featured
-- Bike Helmet | Clearance
-- Smart Watch | New Arrival
-- Air Fryer | Featured
SELECT product_name, category
FROM products
ORDER BY
CASE category
WHEN 'Featured' THEN 1
WHEN 'New Arrival' THEN 2
WHEN 'Sale' THEN 3
ELSE 4
END,
product_name;
-- Output:
-- product_name | category
-- -------------+------------
-- Air Fryer | Featured
-- Desk Lamp | Featured
-- Smart Watch | New Arrival
-- Wool Scarf | Sale
-- Bike Helmet | Clearance
CASE 더 알아보기
이 블로그의 글:
- SQL COALESCE 가이드: 값이 NULL일 때 대체 값을 지정하는 간단한 방법
- SQL 피벗 테이블 가이드: SUM과 AVG 안에 CASE를 넣어 행을 컬럼으로 바꾸기
- SQL ORDER BY 가이드: 사용자 지정 정렬 순서를 포함한 정렬
- SQL GROUP BY 가이드: 조건부 개수와 합계의 기반이 되는 그룹화
- SQL 같지 않음 가이드: NULL과의 비교가 절대 일치하지 않는 이유
공식 문서:
Beekeeper Studio는 무료 오픈 소스 데이터베이스 GUI예요
지금까지 써 본 SQL 쿼리 & 에디터 도구 중 최고예요. 데이터베이스 관리에 필요한 모든 게 다 있어요. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio는 빠르고 직관적이며 사용하기 쉬워요. 다양한 데이터베이스를 지원하고 Windows, Mac, Linux에서 모두 잘 작동해요.
Beekeeper Studio 사용자 후기
"Beekeeper Studio가 기존 SQL 작업 방식을 완전히 대체했어요. 빠르고 직관적이라 데이터베이스 작업이 다시 즐거워졌어요."
"여러 데이터베이스 GUI를 써 봤지만, Beekeeper는 기능과 단순함 사이의 균형이 완벽해요. 그냥 잘 돌아가요."