SQL 코딩 테스트: CASE WHEN 문제 모음

CASE WHEN / 조건부 분류 / 파생 컬럼 — Level 2

Level 2 CASE WHEN 유형 풀이 모음. 조건부 값 분류, END AS 파생 컬럼 생성, CASE 순서와 범위 조건 패턴 등. CASE WHEN + GROUP BY 다중 컬럼 조합, 경계값 처리, NULL 함정 포함.

Code Test
SQL
저자

Kwangmin Kim

공개

2026년 04월 15일

1 문제 1: 직원 급여 등급 분류

1.1 문제 정보

항목 내용
출처 튜터 생성 (앵커: Programmers “조건별로 분류하여 주문상태 출력하기” Lv.2)
난이도 Level 2
SQL 유형 CASE WHEN

1.2 문제 설명

CREATE TABLE employees (
    employee_id INT         PRIMARY KEY,
    name        VARCHAR(50) NOT NULL,
    salary      INT         NOT NULL
);

INSERT INTO employees VALUES
(1, '김철수', 8000),
(2, '이영희', 6000),
(3, '박민수', 9500),
(4, '최지은', 7000),
(5, '정현우', 4500),
(6, '강수진', 5500);

각 직원의 employee_id, name, salary와 급여 등급(grade)을 조회하라. - 등급 기준: salary >= 7000 → ‘상’, 5000 <= salary < 7000 → ‘중’, salary < 5000 → ‘하’ - 정렬: employee_id 오름차순

기대 결과:

employee_id name salary grade
1 김철수 8000
2 이영희 6000
3 박민수 9500
4 최지은 7000
5 정현우 4500
6 강수진 5500

1.3 최종 풀이

SELECT employee_id, name, salary,
    CASE
        WHEN salary >= 7000 THEN '상'
        WHEN salary >= 5000 THEN '중'
        WHEN salary < 5000  THEN '하'
    END AS grade
FROM employees
ORDER BY employee_id ASC;
  • CASE WHEN ... END AS grade: CASE 블록 전체가 하나의 파생 컬럼 — END로 닫고 AS grade로 별칭 부여
  • CASE는 위에서부터 순서대로 매칭 — salary >= 7000이 먼저 처리되므로 두 번째 조건에 salary < 7000을 별도로 쓰지 않아도 된다

1.4 Tips

  • 핵심 개념: CASE WHEN 조건 THEN 값 ... END AS 별칭 — 반드시 END로 닫아야 한다
  • 함정 1: grade는 테이블에 없는 컬럼이다. SELECT ..., grade처럼 독립 컬럼으로 나열하면 오류. CASE WHEN으로 계산해서 END AS grade로 생성해야 한다
  • 함정 2: END 누락 시 파서가 FROM 절까지 CASE 블록으로 해석해 문법 오류 발생
  • : CASE는 위에서 첫 번째 매칭 조건에서 멈춘다. 범위 조건을 넓은 것부터 좁은 것 순으로 쓰면 중간 조건을 단순화할 수 있다

2 문제 2: 카테고리별 가격대별 상품 수 집계

2.1 문제 정보

항목 내용
출처 튜터 생성 (앵커: Programmers “가격대 별 상품 개수 구하기” Lv.2, 정답률 ~65%)
난이도 Level 2
SQL 유형 CASE WHEN + GROUP BY (다중 컬럼) + INNER JOIN

2.2 문제 설명

CREATE TABLE CATEGORY (
    CATEGORY_ID   INT PRIMARY KEY,
    CATEGORY_NAME VARCHAR(50) NOT NULL
);

CREATE TABLE PRODUCT (
    PRODUCT_ID    INT PRIMARY KEY,
    PRODUCT_NAME  VARCHAR(100) NOT NULL,
    CATEGORY_ID   INT,
    PRICE         INT
);

INSERT INTO CATEGORY VALUES
(1, 'Fiction'), (2, 'Science'), (3, 'History');

INSERT INTO PRODUCT VALUES
(101, 'Novel A',        1, 8500),
(102, 'Novel B',        1, 15000),
(103, 'Physics Guide',  2, 50000),
(104, 'Biology 101',    2, 9900),
(105, 'World War II',   3, 120000),
(106, 'Ancient Rome',   3, 45000);

카테고리별로 상품의 가격을 세 구간으로 나누어 구간별 상품 개수(PRODUCT_COUNT)를 집계하는 쿼리를 작성하라.

  • LOW: 10,000원 미만
  • MID: 10,000원 이상 50,000원 미만
  • HIGH: 50,000원 이상
  • 가격이 NULL인 상품은 제외
  • 정렬: 카테고리 이름 오름차순, 같은 카테고리 내에서는 LOW → MID → HIGH 순

기대 결과:

CATEGORY_NAME PRICE_RANGE PRODUCT_COUNT
Fiction LOW 1
Fiction MID 1
History MID 1
History HIGH 1
Science LOW 1
Science HIGH 1

2.3 최종 풀이

SELECT
    c.category_name,
    CASE
        WHEN p.price >= 50000 THEN 'HIGH'
        WHEN p.price >= 10000 AND p.price < 50000 THEN 'MID'
        WHEN p.price < 10000 THEN 'LOW'
    END AS price_range,
    COUNT(*) AS product_count
FROM product p
INNER JOIN category c
    ON c.category_id = p.category_id
WHERE p.price IS NOT NULL
GROUP BY
    c.category_name,
    CASE
        WHEN p.price >= 50000 THEN 'HIGH'
        WHEN p.price >= 10000 AND p.price < 50000 THEN 'MID'
        WHEN p.price < 10000 THEN 'LOW'
    END
ORDER BY
    c.category_name ASC,
    FIELD(price_range, 'LOW', 'MID', 'HIGH');
  • SELECT에 만든 CASE 표현식을 GROUP BY에도 그대로 반복한다. 표준 SQL은 GROUP BY에서 SELECT 별칭 참조를 허용하지 않는다 (MySQL은 예외적으로 허용하지만 이식성 없음)
  • GROUP BY에서는 AS price_range 같은 별칭 부여 불가END까지만 쓰고 잘라야 한다
  • WHERE p.price IS NOT NULL로 NULL을 선필터. ELSE 'LOW'로 잔여를 흡수하면 NULL도 LOW 버킷에 포함된다
  • FIELD(col, v1, v2, v3)는 MySQL 전용으로 문자열 범주의 논리적 정렬 순서를 강제한다. 알파벳 정렬(HIGH, LOW, MID)을 피하는 핵심 도구

2.4 Tips

  • 핵심 개념: CASE WHEN 결과를 GROUP BY 컬럼으로 사용하는 패턴 + 문자열 범주의 논리적 정렬
  • 함정 1 (GROUP BY 별칭 금지): 표준 SQL은 GROUP BY에서 SELECT 별칭 참조 불가. CASE 표현식을 GROUP BY에 반복하거나 인라인 뷰로 감싸야 한다
  • 함정 2 (경계값 >= vs >): “10,000원 이상” = >= 10000, “10,000원 미만” = < 10000. 경계값 자체가 어느 버킷에 속하는지 매번 조건을 읽어 확인할 것
  • 함정 3 (NULL과 ELSE): ELSE 'LOW'는 NULL 가격까지 LOW로 흡수한다. NULL 제외 요구 시 WHERE IS NOT NULL 또는 NULL 전용 버킷 분리 필요
  • 함정 4 (SQL 절 순서): FROM → JOIN ... ON → WHERE → GROUP BY → HAVING → SELECT → ORDER BY. WHERE를 JOIN 앞에 끼워 넣으면 syntax error
  • 함정 5 (문자열 범주 정렬): ORDER BY price_range 만 쓰면 알파벳순(HIGH, LOW, MID). 논리 순서 강제는 FIELD() (MySQL) 또는 ORDER BY CASE price_range WHEN 'LOW' THEN 1 WHEN 'MID' THEN 2 ELSE 3 END (표준)
  • 대안 (인라인 뷰): CASE 중복이 싫으면 서브쿼리로 price_range를 먼저 만든 후 바깥에서 집계. 가독성은 좋지만 Lv.2에서는 오버엔지니어링

2.5 면접 방어 포인트

  • 실행 계획 분석: category_id에 인덱스가 있으면 Index Nested Loop JOIN. GROUP BY는 category_name + CASE 결과로 Hash Aggregation. 단일 쿼리와 인라인 뷰는 대부분 옵티마이저가 동일하게 펼친다
  • 대안 비교: (1) CASE 반복 방식 — 표준 SQL 호환, 유지보수 시 양쪽 동기화 부담. (2) 인라인 뷰 — CASE 1회 정의, 추가 스캔 가능성. (3) MySQL 별칭 참조 — 가장 짧지만 방언 종속
  • 통계적 관점: 버킷 수가 3개로 고정되므로 GROUP BY 결과 행 수는 최대 카테고리 수 × 3. 대용량에서도 출력 크기가 예측 가능하다
  • NULL 의미론: “가격 미정”을 집계에서 제외할지, 별도 ‘UNKNOWN’ 버킷으로 둘지는 비즈니스 결정. WHERE로 제외하는 선택은 “집계 대상이 아님”을 명시적으로 드러낸다
  • 방언 호환: FIELD()는 MySQL 전용. PostgreSQL·Oracle 이식 시 ORDER BY CASE ... END로 전환 필요

3 관련 문제

Subscribe

Enjoy this blog? Get notified of new posts by email: