공공부하자개발 · 영어 학습 노트
SQL
SQL 중급서브쿼리·조인·함수·DDL·인덱스0/11 완료
  • 01서브쿼리: 스칼라·인라인 뷰·상관 서브쿼리, DB별 차이
  • 02EXISTS·IN·NOT IN 과 NULL 함정
  • 03조인 심화: INNER·OUTER·SELF·CROSS, Oracle (+)
  • 04집합 연산: UNION·UNION ALL·INTERSECT·MINUS/EXCEPT
  • 05조건 로직: CASE·DECODE·IIF
  • 06NULL 처리 함수
  • 07문자·날짜 함수 DB별 비교
  • 08DDL 과 제약 조건
  • 09인덱스 기초
  • 10집계와 GROUP BY·HAVING
  • 11뷰·시퀀스·자동 증가
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › SQL 중급 › 05 / 11

조건 로직: CASE·DECODE·IIF

섹션 6진행 0 / 11
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6정리‹ 이전다음 ›

4. 응용 변형 예제

소스: sql-src/mid_05_case/02_conditional_agg.sql, 03_dialects.sql. 조건부 집계, UPDATE 에서의 CASE, DB 별 편의 함수 차이를 확인합니다. orders 테이블에 부서별·상태별 주문 12건을 추가했습니다.

변형 1: SUM(CASE ...) 로 부서별 상태 금액을 행에서 열로

sql
SELECT
       e.dept
     , SUM(CASE WHEN o.status = '완료' THEN o.amt ELSE 0 END) AS amt_done
     , SUM(CASE WHEN o.status = '취소' THEN o.amt ELSE 0 END) AS amt_cancel
     , SUM(CASE WHEN o.status = '보류' THEN o.amt ELSE 0 END) AS amt_hold
  FROM orders o
  JOIN emp e ON e.id = o.emp_id
 GROUP BY e.dept
 ORDER BY e.dept;
text
DEPT | AMT_DONE | AMT_CANCEL | AMT_HOLD
-----+----------+------------+---------
개발 | 1200     | 300        | 200
영업 | 1300     | 150        | 0
인사 | 0        | 300        | 180
지원 | 620      | 0          | 0
(4행)

상태마다 SUM(CASE ...) 을 하나씩 늘어놓으면 GROUP BY 한 번으로 상태별 금액이 컬럼으로 펼쳐집니다. 해당 상태가 아닌 행은 CASE 가 0 을 돌려주므로 SUM 에 영향을 주지 않습니다.

팁

이렇게 상태 값을 미리 아는 소수의 컬럼으로 펼치는 정도라면 CASE 조합으로 충분합니다. 컬럼 목록을 데이터에 따라 동적으로 정해야 하는 본격 PIVOT 은 고급 05 에서 다룹니다.

변형 2: COUNT(CASE ...) 로 상태별 건수 한 줄 리포트

sql
SELECT
       COUNT(*) AS total_cnt
     , COUNT(CASE WHEN o.status = '완료' THEN 1 END) AS done_cnt
     , COUNT(CASE WHEN o.status = '취소' THEN 1 END) AS cancel_cnt
     , COUNT(CASE WHEN o.status = '보류' THEN 1 END) AS hold_cnt
  FROM orders o;
text
TOTAL_CNT | DONE_CNT | CANCEL_CNT | HOLD_CNT
----------+----------+------------+---------
12        | 7        | 3          | 2
(1행)

COUNT 는 NULL 을 세지 않는다는 성질을 이용했습니다. CASE 가 조건에 안 맞는 행에 ELSE 없이 NULL 을 돌려주면 COUNT(CASE ...) 는 그 행을 건너뛰고, 조건에 맞는 행만 1 로 세어 건수를 구합니다. 7 + 3 + 2 = 12로 전체 건수와도 맞습니다.

변형 3: UPDATE 에 CASE 로 부서마다 다른 인상률 한 번에 반영

sql
UPDATE emp
   SET sal =
       CASE WHEN dept = '개발' THEN sal + 50
            WHEN dept = '영업' THEN sal + 30
            ELSE sal
       END
 WHERE dept IN ('개발', '영업', '인사');

개발·영업·인사 세 부서를 한 번에 걸러 놓고, 부서별로 다른 인상액은 CASE 로 나눴습니다. 실행 뒤 조회하면 개발은 50, 영업은 30 이 오르고 인사는 ELSE 의 sal(원래 값)이 그대로 들어가 안 바뀐 것을 확인할 수 있습니다. WHERE 절의 부서 목록과 CASE 안의 부서 조건이 겹치지만, 이렇게 하면 부서별 UPDATE 문을 여러 번 나눠 쓰지 않아도 됩니다.

변형 4: DB 별 지원 현황

기능 Oracle · Tibero MySQL MSSQL
CASE(단순·검색) 지원 지원 지원
DECODE 지원 없음 없음
IF(cond, a, b) 없음 지원 없음
IIF(cond, a, b) 없음 없음 지원(2012 부터)
CHOOSE(i, ...) 없음 없음 지원(2012 부터)
주의

IIF·CHOOSE 는 MSSQL 2012 이전 버전에는 없습니다. 배포 대상 MSSQL 버전이 그보다 낮다면 CASE 로 써야 하고, 확신이 없으면 처음부터 CASE 로 작성하는 편이 안전합니다.

변형 5: Oracle DECODE 실행과 NULL 비교 차이

DECODE 는 단순 CASE 와 같은 자리에서 값을 비교해 바꿔치기하는 Oracle·Tibero 전용 함수입니다. mgr 컬럼은 대표이사인 김대표만 NULL 이고, DECODE 로 NULL 여부를 표시해 봅니다.

sql
SET MODE Oracle;
SELECT
       name
     , DECODE(mgr, NULL, '없음', '있음') AS mgr_flag
  FROM emp
 ORDER BY id;
text
NAME   | MGR_FLAG
-------+---------
김대표 | 없음
이팀장 | 있음
박선임 | 있음
최사원 | 있음
정팀장 | 있음
서팀장 | 있음
강팀장 | 있음
한주임 | 있음
문사원 | 있음
오사원 | 있음
(10행)
sql
SELECT
       name
     , CASE mgr WHEN NULL THEN '없음' ELSE '있음' END AS mgr_flag
  FROM emp
 ORDER BY id;
text
NAME   | MGR_FLAG
-------+---------
김대표 | 있음
이팀장 | 있음
박선임 | 있음
최사원 | 있음
정팀장 | 있음
서팀장 | 있음
강팀장 | 있음
한주임 | 있음
문사원 | 있음
오사원 | 있음
(10행)

DECODE 는 김대표의 NULL 을 두 번째 인자 NULL 과 같다고 보고 없음을 돌려줬습니다. 단순 CASE 는 내부적으로 mgr = NULL 비교라 김대표를 포함해 모든 행이 있음(ELSE)으로 빠졌습니다. 2.5절에서 설명한 차이가 그대로 재현됩니다.

변형 6: MySQL·MSSQL 편의 함수는 H2 미지원, CASE 로 대체

sql
SET MODE MySQL;
SELECT IF(sal > 500, 'Y', 'N') FROM emp;
text
예상 오류: Syntax error in SQL statement
sql
SET MODE MSSQLServer;
SELECT IIF(sal > 500, 'Y', 'N') FROM emp;
text
예상 오류: Function "IIF" not found
sql
SELECT CHOOSE(1, 'a', 'b', 'c') FROM emp;
text
예상 오류: Function "CHOOSE" not found

이 레슨의 H2 는 MySQL 모드에서 IF() 를 문법 오류로, MSSQL 모드에서 IIF·CHOOSE 를 "함수를 찾을 수 없음" 오류로 거절합니다. 셋 다 "H2 미지원, 문법 검토만"이며 실제 MySQL·MSSQL(2012 부터)에서는 정상 동작하는 함수입니다. 세 함수 모두 같은 검색 CASE 로 대체됩니다.

sql
SELECT
       name
     , CASE WHEN sal > 500 THEN 'Y' ELSE 'N' END AS flag
  FROM emp
 ORDER BY id;
text
NAME   | FLAG
-------+-----
김대표 | Y
이팀장 | Y
박선임 | N
최사원 | N
정팀장 | Y
서팀장 | Y
강팀장 | N
한주임 | N
문사원 | N
오사원 | N
(10행)

IF(cond, a, b)·IIF(cond, a, b) 는 CASE WHEN cond THEN a ELSE b END 와 뜻이 완전히 같습니다. CHOOSE(i, v1, v2, ...) 는 순번 i 로 값을 고르는 함수라 CASE i WHEN 1 THEN v1 WHEN 2 THEN v2 ... END 로 옮길 수 있습니다. 이 레슨 데이터에는 순번으로 고를 컬럼이 따로 없어 CHOOSE 대체 쿼리는 개념만 짚고 넘어갑니다.

응용 변형 예제
  • 변형 1: SUM(CASE ...) 로 부서별 상태 금액을 행에서 열로
  • 변형 2: COUNT(CASE ...) 로 상태별 건수 한 줄 리포트
  • 변형 3: UPDATE 에 CASE 로 부서마다 다른 인상률 한 번에 반영
  • 변형 4: DB 별 지원 현황
  • 변형 5: Oracle DECODE 실행과 NULL 비교 차이
  • 변형 6: MySQL·MSSQL 편의 함수는 H2 미지원, CASE 로 대체
이전 섹션3 코드 예제4 / 6다음 섹션5 자주 하는 실수 (Tip)