✅ CASE
IF ELSE THEN
처럼, 특정조건에 따라 다른 값을 출력하게 하는 SQL의 강력한 조건부 로직WHEN
조건들 중에서 어느것도 하나도 참이 아닌 경우, ELSE
뒤의 결과를 반환
만약 ELSE
를 생략했는데, 모든 WHEN
조건이 거짓이면 NULL
이 반환됨
💡 위에서 아래 순서로 조건을 평가하며, 먼저 참이되는 WHERE
절을 만나면
THEN
의 결과를 반환하고 다른 조건은 보지 않는다
CASE 문의 문법은 다음과 같다
// 문법 (CASE WHEN ELSE END)
CASE 비교대상_컬럼_또는_표현식
WHEN 값1 THEN 결과1
WHEN 값2 THEN 결과2
...
ELSE 그_외의_경우_결과
END
CASE
문은 크게 단순 CASE 문
과 검색 CASE 문
으로 나뉜다
단순 CASE문
: 표현식의 값에 따라 결과를 다르게 하고 싶을 때 사용
select status ,
case
when status = 'COMPLETED' then '완료'
when status = 'SHIPPED' then '배송중'
when status = 'PENDING' then '대기'
else '알수없음'
end as status_korean // 별칭부여
from orders;
검색 CASE문
: WHEN
절에 독립적인 조건식을 사용하여 복 잡한 논리를 구현할 때 사용
비교 연산자와 논리 연산자를 사용할 수 있다 (AND OR NOT)
SELECT
name,
price,
CASE
WHEN price >= 100000 THEN '고가'
WHEN price >= 30000 THEN '중가'
ELSE '저가'
END AS price_label
FROM products;
CASE
문은 SELECT
절 외에도 ORDER BY
GROUP BY
WHERE
등 다양한 곳에서 사용할 수 있다
만약 상품을 '고가' '중가' '저가' 순으로 정렬하고 싶다고 가정해보자
SELECT
name,
price,
CASE
WHEN price >= 100000 THEN '고가'
WHEN price >= 30000 THEN '중가'
ELSE '저가'
END AS price_label
FROM products
ORDER BY
CASE
WHEN price >= 100000 THEN 1 -- 고가: 1
WHEN price >= 30000 THEN 2 -- 중가: 2
ELSE 3 -- 저가: 3
END ASC, -- 숫자가 작은 순서대로 정렬 (1순위 정렬 기준)
price DESC; -- 같은 등급 내에서는 가격 내림차순 (2순위 정렬 기준)
이번엔 CASE
문을 GROUP BY
에 넣은 예시를 확인하자
고객들을 출생 연대에 따라 '1990년대생', '1980년대생', '그 이전 출생'으로 분류하고, 각 그룹에 고객이 총 몇 명씩 있는 조회
라는 문제가 있다고 가정하자
문제를 해결하면 ORDER BY
에서 해결한 것처럼 GROUP BY
뒤에 CASE문을 그대로 넣어줘야한다
SELECT
CASE
WHEN YEAR(birth_date) >= 1990 THEN '1990년대생'
WHEN YEAR(birth_date) >= 1980 THEN '1980년대생'
ELSE '그 이전 출생'
END AS birth_decade,
COUNT(*) AS customer_count
FROM users
GROUP BY
CASE
WHEN YEAR(birth_date) >= 1990 THEN '1990년대생'
WHEN YEAR(birth_date) >= 1980 THEN '1980년대생'
ELSE '그 이전 출생'
END;
하지만 CASE문으로 조회한 결과값의 별칭을 GROUP BY 뒤에 넣어줘도 그룹핑이 된다
원래의 SQL 표준 논리적 실행순서에 따르면 GROUP BY
절이 SELECT
절보다 먼저 처리되기 때문에
CASE문으로 조회한 결과값 (birth_decade) 을 GROUP BY
절에 사용할 수 없지만
편의를 위해서 많은 데이터베이스들이 이러한 별칭 사용은 예외적으로 허용하게 해놨다
SELECT
CASE
WHEN YEAR(birth_date) >= 1990 THEN '1990년대생'
WHEN YEAR(birth_date) >= 1980 THEN '1980년대생'
ELSE '그 이전 출생'
END AS birth_decade,
COUNT(*) AS customer_count
FROM users
GROUP BY birth_decade
✅ 조건부 집계
CASE
문이 집계함수 (SUM, COUNT) 등의 안으로 들어가는 방법EX) 하나의 쿼리로, 전체 주문 건수와 함께 '결제 완료(COMPLETED)', '배송(SHIPPED)', '주문 대기(PENDING)' 상태의 주문이 각각 몇 건인지 별도의 컬럼으로 나누기
이 문제는 두가지 방법으로 해결할 수 있다
COUNT
안에 CASE
문 작성하기SELECT
COUNT(*) AS total_orders,
COUNT(CASE WHEN status = 'COMPLETED' THEN 1 END) AS completed_count,
COUNT(CASE WHEN status = 'SHIPPED' THEN 1 END) AS shipped_count,
COUNT(CASE WHEN status = 'PENDING' THEN 1 END) AS pending_count
FROM
orders
SUM
안에 CASE
문 작성하기SELECT
COUNT(*) AS total_orders,
SUM(CASE WHEN status = 'COMPLETED' THEN 1 ELSE 0 END) AS completed_count,
SUM(CASE WHEN status = 'SHIPPED' THEN 1 ELSE 0 END) AS shipped_count,
SUM(CASE WHEN status = 'PENDING' THEN 1 ELSE 0 END) AS pending_count
FROM
orders;
COUNT
에서 ELSE 0 을 안적은 이유는 COUNT
는 NULL 일 경우 세지 않음
즉 WHEN
이 거짓이면 NULL로 나와서 자동으로 세지 않음
하지만 ELSE 0을 적어버리면 0은 NULL이 아니기 때문에 세버림