조건식
CASE · IIF · CHOOSE 로 값에 따라 다른 것을 냅니다. 집계 안에 넣어 한 줄에 여러 셈을 내는 방법이 핵심입니다.
값에 따라 다른 것을 냅니다
지금까지는 담긴 값을 그대로 내거나 함수로 가공했습니다(1.10).
CASE 는 조건을 보고 낼 값을 정합니다.
두 가지 형태가 있습니다. 조건을 하나씩 적는 것과, 열 하나의 값을 여러 개와 비교하는 것입니다.
-- 조건을 하나씩 적습니다(검색 CASE) SELECT TOP 6 num, hit_count, CASE WHEN hit_count >= 400 THEN N'높음' WHEN hit_count >= 200 THEN N'보통' ELSE N'낮음' END AS 등급 FROM Board.POSTS WHERE num IN (1, 60, 70, 140, 214, 300) ORDER BY num;
| num | hit_count | 등급 |
|---|---|---|
| 1 | 7 | 낮음 |
| 60 | 420 | 높음 |
| 70 | 490 | 높음 |
| 140 | 480 | 높음 |
| 214 | 498 | 높음 |
| 300 | 100 | 낮음 |
위에서부터 보다가 처음 참인 것에서 멈춥니다. 그래서 범위 조건을 적을 때는 차례가 중요합니다. 위 문장에서 400 과 200 을 바꿔 적으면 420 짜리 글도 "보통" 이 됩니다.
값 하나를 여럿과 견줄 때
SELECT TOP 3 num, board_num, CASE board_num WHEN 1 THEN N'공지' WHEN 2 THEN N'자유' WHEN 3 THEN N'질문' END AS 게시판 FROM Board.POSTS ORDER BY num;
| num | board_num | 게시판 |
|---|---|---|
| 1 | 2 | 자유 |
| 2 | 2 | 자유 |
| 3 | 2 | 자유 |
짧지만 같음(=) 비교만 됩니다. 범위나 IS NULL 을
써야 하면 검색 형태로 적어야 합니다.
이 예제는 설명을 위한 것입니다. 실제로는 게시판 이름을 문장에 박아 넣지 말고
Board.BOARDS 와 조인하십시오(2.1). 이름이 바뀌면 문장을
찾아 고쳐야 하기 때문입니다.
ELSE 를 빠뜨리면 NULL
SELECT CASE WHEN 1 = 2 THEN N'참' END AS else없음, CASE WHEN 1 = 2 THEN N'참' ELSE N'거짓' END AS else있음;
| else없음 | else있음 |
|---|---|
| NULL | 거짓 |
어느 조건에도 걸리지 않으면 NULL 입니다.
그 값을 이어 붙이거나 셈에 넣으면 결과가 통째로 NULL 이 됩니다(1.5 · 1.9).
빠뜨리기 쉬우니 ELSE 를 습관으로 적으십시오.
짧게 줄인 형태
SELECT IIF(10 > 5, N'크다', N'작다') AS iif결과, CHOOSE(2, N'첫째', N'둘째', N'셋째') AS choose결과, CHOOSE(9, N'첫째', N'둘째') AS 범위밖;
| iif결과 | choose결과 | 범위밖 |
|---|---|---|
| 크다 | 둘째 | NULL |
| 함수 | 같은 뜻의 CASE |
|---|---|
| IIF(조건, A, B) | CASE WHEN 조건 THEN A ELSE B END |
| CHOOSE(n, …) | n 번째를 냅니다. 범위를 벗어나면 NULL |
| COALESCE(A, B) | CASE WHEN A IS NOT NULL THEN A ELSE B END (1.9) |
| NULLIF(A, B) | CASE WHEN A = B THEN NULL ELSE A END (1.9) |
IIF 와 CHOOSE 는 SQL Server
전용입니다. 경우가 둘뿐이면 짧아서 좋지만, 셋 이상이면
CASE 가 읽기 좋습니다. 조건과 결과가 나란히
보이기 때문입니다.
조건부 집계 — 한 줄에 여러 셈
이 단원에서 가장 쓸모 있는 용법입니다. 집계 함수 안에
CASE 를 넣으면 조건마다 따로 셀 수 있습니다.
2.2 에서 게시판별 원글과 답글을 세려면 GROUP BY board_num, depth
로 묶어 일곱 줄이 나왔습니다. 그것을 게시판당 한 줄로 냅니다.
SELECT board_num, COUNT(*) AS 전체, SUM(CASE WHEN depth = 0 THEN 1 ELSE 0 END) AS 원글, SUM(CASE WHEN depth > 0 THEN 1 ELSE 0 END) AS 답글, COUNT(CASE WHEN hit_count >= 400 THEN 1 END) AS 인기글 FROM Board.POSTS GROUP BY board_num ORDER BY board_num;
| board_num | 전체 | 원글 | 답글 | 인기글 |
|---|---|---|---|---|
| 1 | 35 | 35 | 0 | 8 |
| 2 | 315 | 210 | 105 | 39 |
| 3 | 157 | 105 | 52 | 18 |
두 가지 방식을 함께 보여 주었습니다.
-
SUM(CASE … THEN 1 ELSE 0 END)— 맞으면 1, 아니면 0 을 더합니다. -
COUNT(CASE … THEN 1 END)— 맞으면 1, 아니면 NULL 인데COUNT가 NULL 을 빼고 세므로(2.2) 같은 결과가 됩니다.ELSE를 적지 않는 것이 요령입니다.
둘 다 익혀 두십시오. 남의 코드에서 두 형태를 모두 보게 됩니다. 공지사항의 답글이 0 인 것은 그 게시판이 답글을 받지 않기 때문입니다(1.2).
이 방식으로 행을 열로 돌리는 것이 다음 단원의 PIVOT 입니다(2.9).
정렬 기준을 계산해서 만들기
1.7 에서 NULL 이 오름차순 맨 앞에 놓이는 것을 보고,
"값이 있는 것을 먼저 보려면 정렬 기준을 계산해야 한다" 고만 적었습니다. 그 방법이
CASE 입니다.
SELECT TOP 6 num, nickname, email FROM Member.USERS ORDER BY CASE WHEN email IS NULL THEN 1 ELSE 0 END, email;
| num | nickname | |
|---|---|---|
| 20 | 안지호 | ahn@example.com |
| 17 | 백나윤 | baek@example.com |
| 11 | 한소망 | han@example.com |
| 1 | 홍길동 | hong@example.com |
| 6 | 정하늘 | jung@example.com |
| 7 | 강바다 | kang@example.com |
1.7 에서는 전자 메일이 없는 넷이 먼저 나왔는데, 이제 뒤로 갔습니다. 값이 있으면 0, 없으면 1 을 매겨 그것으로 먼저 정렬했기 때문입니다.
ORDER BY 에 적은 식은 결과에 나오지 않아도
됩니다. 화면에는 0 과 1 이 보이지 않습니다.
WHERE 에서는 대개 필요 없습니다
CASE 는 WHERE 에도 사용할 수 있지만,
같은 뜻을 AND · OR 로 적을
수 있다면 그쪽이 낫습니다.
-- 굳이 CASE 로 SELECT COUNT(*) AS case로 FROM Board.POSTS WHERE CASE WHEN board_num = 1 THEN hit_count ELSE 0 END >= 400; -- 같은 뜻, 더 짧고 인덱스도 사용합니다 SELECT COUNT(*) AS and로 FROM Board.POSTS WHERE board_num = 1 AND hit_count >= 400;
| case로 | and로 |
|---|---|
| 8 | 8 |
결과는 같지만 앞엣것은 인덱스를 사용하지 못합니다. 열을 식으로
감쌌기 때문입니다(1.10 · 5.4). CASE 는
낼 값을 정할 때 쓰고, 남길 행을 정하는 일은
WHERE 의 조건에 맡기십시오.
직접 해보기
회원 목록에 전자 메일이 있으면 그 주소를, 없으면 미등록 을
내되 CASE 로 적어 보세요. 그다음
COALESCE 로도 적어 두 결과가 같은지 확인하십시오.
회원마다 작성한 글 수와 그중 원글 수·답글 수를 한 줄로 내고, 많이 작성한 사람부터 다섯 명만 보이게 해보세요.
CASE는 위에서부터 보다가 처음 참인 것에서 멈춥니다. 범위 조건은 차례가 중요합니다.ELSE가 없으면 NULL 입니다. 습관으로 적으십시오.COALESCE·NULLIF·IIF는 모두CASE의 축약입니다.- 집계 안의
CASE로 한 줄에 여러 셈을 냅니다.SUM(CASE … THEN 1 ELSE 0 END)또는COUNT(CASE … THEN 1 END)입니다. ORDER BY에CASE를 두면 NULL 을 뒤로 보낼 수 있습니다.WHERE에서는AND·OR로 적으십시오. 인덱스를 사용하지 못합니다.