CASE는 SQL의 If/Else다
CASE는 쿼리 안에서 조건 분기를 처리하는 방법이다. 위에서부터 WHEN 분기를 순서대로 훑어가다가 처음으로 조건이 맞는 곳에서 멈추고, 그 뒤의 THEN 값을 돌려준다. 어디에도 걸리지 않으면 ELSE 값이 나오고, ELSE조차 없으면 NULL이 반환된다.
여기서 핵심은 _표현식_이라는 점이다. CASE는 값을 만들어내기 때문에, 값을 쓸 수 있는 자리라면 어디든 들어갈 수 있다. SELECT의 컬럼, ORDER BY의 정렬 키, 비교 연산의 우변, 함수의 인자 — 어느 자리든 상관없다.
전체 구조는 이렇게 정리됩니다. CASE로 시작해서 WHEN ... THEN ...을 하나 이상 쓰고, 필요하면 ELSE를 붙인 뒤 마지막에 END로 닫습니다. END는 빠뜨리면 안 되는 필수 키워드인데, 실수로 가장 자주 빼먹는 부분이기도 합니다.
실전 예제로 살펴보는 sqlite case when
주문 테이블이 있고, 각 행을 금액 규모별로 라벨링하고 싶다고 해봅시다. 바로 돌려볼 수 있도록 간단한 테이블을 만들어 데이터를 넣어두겠습니다:
분기는 위에서 아래로 차례대로 검사되고, 가장 먼저 매칭된 조건이 채택됩니다. 그래서 구체적인 조건일수록 먼저 적고, 일반적인 조건은 뒤로 빼는 게 좋아요. 마지막의 ELSE는 어디에도 걸리지 않은 값을 받아주는 안전망 역할을 합니다. 만약 ELSE가 없으면 1200.00은 '큼'가 아니라 NULL로 떨어지게 됩니다.
검색 case 표현식 vs 단순 case 표현식
방금 본 형태가 바로 검색(searched) 방식입니다. 각 WHEN 절마다 독립된 불리언 조건을 적는 방식이죠. 하나의 식을 여러 상수값과 비교하기만 하면 될 때는 좀 더 간결한 단순(simple) 형태를 쓸 수 있습니다.
CASE 뒤에 오는 표현식은 한 번만 계산된 다음, 각 WHEN 값과 = 연산자로 비교됩니다. 단일 컬럼에서 동등 비교만 할 때는 이 방식이 훨씬 깔끔합니다.
한 가지 주의할 점이 있습니다. 단순 CASE는 =로 비교하는데, SQL에서 NULL = NULL은 참이 아닙니다. 그래서 status 값이 NULL일 수 있다면 'A', 'B', 'C' 분기 어디에도 걸리지 않고 결국 ELSE로 빠집니다. NULL을 명시적으로 처리하려면 검색 case 표현식으로 바꿔서 WHEN status IS NULL THEN ...처럼 작성해야 합니다.
ORDER BY에서 CASE WHEN 활용하기
ORDER BY는 어떤 표현식이든 받을 수 있어서 CASE도 그대로 쓸 수 있습니다. 알파벳순이나 숫자순으로는 표현이 안 되는 커스텀 정렬 순서가 필요할 때 특히 유용합니다.
'high' < 'low' < 'medium' 처럼 알파벳 순으로 정렬되는데, 우선순위 분류엔 전혀 쓸모가 없죠. 각 우선순위를 CASE로 숫자에 매핑하면 원하는 순서를 정확히 얻을 수 있습니다. 끝에 붙인 , id는 동점일 때 안정적으로 순서를 잡아주는 역할을 합니다.
WHERE 절에서 CASE 사용하기
WHERE 안에 CASE를 넣는 것도 가능하지만, 대부분의 경우엔 굳이 그럴 필요가 없습니다. AND/OR로 엮는 편이 훨씬 읽기 쉽거든요. 진짜 빛을 발하는 순간은 조건 자체 가 다른 값에 따라 달라질 때입니다:
세일 상품은 20 미만, 일반 상품은 30 미만일 때 조건을 만족합니다. 즉, 기준값 자체가 조건에 따라 달라지는 거죠. CASE 없이 작성한다면 (on_sale = 1 AND price < 20) OR (on_sale = 0 AND price < 30)처럼 써야 합니다. 결과는 같지만 훨씬 지저분하죠.
집계 함수 안에서 CASE 사용하기
CASE가 진가를 발휘하는 지점이 바로 여기입니다. SUM이나 COUNT와 함께 쓰면 한 번의 스캔만으로 특정 조건을 만족하는 행만 골라 합계나 개수를 계산할 수 있습니다. SQL에서 "이 조건에 해당하는 게 몇 개야?"를 표현하는 가장 깔끔한 방법이죠:
CASE가 조건에 해당하는 행에는 1을, 그렇지 않은 행에는 0을 반환하기 때문에 SUM이 자연스럽게 조건부 카운트가 됩니다. 매출도 같은 방식으로 처리할 수 있죠. 조건에 맞는 행에는 total을, 나머지에는 0을 돌려주면 끝입니다. 테이블을 한 번만 훑으면서 여러 개의 조건부 집계를 한꺼번에 뽑아내는 방법입니다.
IIF 함수: 두 갈래 분기를 위한 단축 표현
조건이 하나이고 결과가 두 가지뿐이라면, SQLite의 IIF(cond, when_true, when_false)를 쓰면 됩니다. CASE WHEN cond THEN when_true ELSE when_false END를 짧게 줄인 형태일 뿐, 동작은 완전히 동일합니다:
IIF는 조건이 둘로 갈리고 한 줄로 쓰는 게 더 깔끔할 때 쓰면 좋습니다. 반대로 분기가 세 개 이상이거나, NULL을 따로 처리해야 하거나, 여러 WHEN 절을 순서대로 흘려보내며 매칭시키고 싶다면 CASE로 갈아타세요.
자주 마주치는 함정들
실무에서 사람들이 흔히 걸려 넘어지는 포인트 몇 가지를 짚어보겠습니다.
END빼먹기.CASE로 블록을 열었으면 반드시END로 닫아야 합니다. 빠뜨리면 SQLite가 파싱 에러를 내뱉는데, 실제 실수 위치에서 한참 떨어진 곳에서 에러가 나서 디버깅이 까다롭습니다.ELSE가 없으면NULL이 나옵니다. 어떤WHEN분기에도 매칭되지 않았는데ELSE까지 생략하면 결과는NULL이 됩니다. 의도한 동작일 때도 있지만, 보통은 그렇지 않죠.- 분기 순서가 결과를 좌우합니다. 검색 case 표현식에서는 가장 먼저 매칭된
WHEN이 채택됩니다.WHEN total < 500을WHEN total < 100보다 앞에 두면 뒤쪽 분기는 영영 닿지 않는 죽은 코드가 됩니다. - 타입이 섞이는 문제. 각 분기가 서로 다른 타입을 반환해도 SQLite는 군말 없이 받아주지만, 그 결과를 받아 쓰는 쪽 코드에서 문제가 터질 수 있습니다. 가급적 모든 분기가 호환되는 타입(전부 문자열이든, 전부 숫자든)을 돌려주도록 맞춰주세요.
- 단순 case 표현식과
NULL. 앞서 언급한 대로, 단순 형태는 내부적으로=로 비교하기 때문에NULL에는 절대 매칭되지 않습니다.NULL이 끼어 있을 가능성이 있으면 검색 형태를 쓰세요.
다음 장: 문자열 함수
CASE가 값에 따라 분기하는 도구였다면, 다음 장부터는 값을 변형 하는 영역으로 넘어갑니다. UPPER, LOWER, SUBSTR, REPLACE, LIKE 패턴 같은 문자열 함수들은 텍스트 컬럼을 정리하고 형식을 다시 맞추는, 가장 일상적인 작업을 책임집니다. 바로 이어서 다뤄보겠습니다.
자주 묻는 질문
SQLite의 CASE 표현식이란 뭔가요?
CASE는 SQL판 if/else라고 보면 됩니다. 조건을 차례로 평가해서 값을 돌려주죠. 중요한 건 _문(statement)_이 아니라 _표현식(expression)_이라는 점인데요, 그래서 값이 들어갈 수 있는 자리라면 어디든 쓸 수 있습니다. SELECT, WHERE, ORDER BY, UPDATE는 물론이고 집계 함수 안에서도 가능해요. 각 분기는 WHEN 조건 THEN 값 형태이고, 마지막에 ELSE를 선택적으로 붙일 수 있습니다.
단순(simple) CASE와 검색(searched) CASE는 어떻게 다른가요?
단순 CASE는 하나의 식을 여러 값과 비교합니다. 예를 들면 CASE status WHEN 'A' THEN ... WHEN 'B' THEN ... END 같은 형태죠. 반면 검색 CASE는 분기마다 별도의 불리언 조건을 평가합니다. CASE WHEN price > 100 THEN ... WHEN qty = 0 THEN ... END 처럼요. 검색형이 훨씬 유연해서 여러 컬럼, 비교 연산자, NULL 체크를 자유롭게 섞어 쓸 수 있습니다.
CASE 대신 IIF를 써야 할 때는 언제인가요?
IIF(cond, a, b)는 CASE WHEN cond THEN a ELSE b END의 축약형입니다. 두 갈래 분기처럼 단순한 경우엔 IIF가 훨씬 읽기 좋아요. 다만 분기가 3개 이상이거나, 조건의 평가 순서가 중요하거나, WHEN col IS NULL처럼 NULL을 명시적으로 처리해야 한다면 CASE가 정답입니다.