CASE는 생각보다 다양한 곳에 사용할 수 있다.
GROUP BY에 컬럼을 변형해 사용할 수 있는 것처럼 GROUP BY에 CASE도 사용할 수 있다. 아래는 CASE를 적용한 항목 자체를 GROUP BY 처리하는 예제다. CASE를 사용해 ShopDv를 처리하고 ShopDv에 따라 데이터를 그룹핑한다.
-- [SQL-6-2-1]
-- GROUP BY 적용 전 SQL
-- CASE를 사용해 S001 매장과 나머지 매장으로 구분해서 ShopDv를 출력
SELECT T1.ShopId
,CASE WHEN T1.ShopId = 'S001' THEN 'S001매장' ELSE '나머지매장' END ShopDv
,T1.OrdDtm
,T1.OrdNo
,T1.OrdAmt
FROM startdb.Ord T1
WHERE T1.OrdDtm >= STR_TO_DATE('20230330','%Y%m%d')
AND T1.OrdDtm < STR_TO_DATE('20230331','%Y%m%d')
ORDER BY T1.ShopId;
ShopId ShopDv OrdDtm OrdNo OrdAmt
------ -------- ------------------- ----- ---------
S001 S001매장 2023-03-30 16:00:00 89036 4500.000
S001 S001매장 2023-03-30 16:00:00 89094 5000.000
... 생략 ...
S272 나머지매장 2023-03-30 12:30:00 88283 4000.000
S274 나머지매장 2023-03-30 12:30:00 88284 4500.000
-- [SQL-6-2-2]
-- CASE를 사용한 ShopDv 로직을 GROUP BY에 그대로 사용
SELECT CASE WHEN T1.ShopId = 'S001' THEN 'S001매장' ELSE '나머지매장' END ShopDv
,SUM(T1.OrdAmt) OrdAtm
FROM startdb.Ord T1
WHERE T1.OrdDtm >= STR_TO_DATE('20230330','%Y%m%d')
AND T1.OrdDtm < STR_TO_DATE('20230331','%Y%m%d')
GROUP BY CASE WHEN T1.ShopId = 'S001' THEN 'S001매장' ELSE '나머지매장' END;
ShopDv OrdAtm
---------- ------------
나머지매장 13209500.000
S001매장 1399000.000
아래는 주문시간대구분을 CASE로 처리한 후에, GROUP BY 처리한 예다. 어느 시간대 주문이 많은지 확인하는데 도움이 될 수 있다.
-- [SQL-6-2-3]
-- GROUP BY 적용전 SQL
-- DATE_FORMAT을 사용해 OrdDtm의 시간 부분을 추출하고 그에 따라 주문시간대구분을 처리
SELECT T1.OrdNo ,T1.OrdDtm ,DATE_FORMAT(T1.OrdDtm,'%H') 주문시간
,CASE WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '10' THEN '10시이전주문'
WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '12' THEN '12시이전주문'
WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '17' THEN '17시이전주문'
ELSE '17시이후주문'
END 주문시간대구분
FROM startdb.Ord T1
WHERE T1.OrdDtm >= STR_TO_DATE('20201205','%Y%m%d')
AND T1.OrdDtm < STR_TO_DATE('20201206','%Y%m%d')
ORDER BY T1.OrdDtm ASC;
OrdNo OrdDtm 주문시간 주문시간대구분
----- ------------------- -------- --------------
7585 2020-12-05 08:00:00 08 10시이전주문
7586 2020-12-05 08:00:00 08 10시이전주문
... 생략 ...
7663 2020-12-05 13:00:00 13 17시이전주문
7664 2020-12-05 13:00:00 13 17시이전주문
-- [SQL-6-2-4]
-- GROUP BY 적용후 SQL, CASE를 GROUP BY 항목으로 사용
SELECT CASE WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '10' THEN '10시이전주문'
WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '12' THEN '12시이전주문'
WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '17' THEN '17시이전주문'
ELSE '17시이후주문'
END 주문시간대구분
,COUNT(*) 주문시간대별주문건수
FROM startdb.Ord T1
WHERE T1.OrdDtm >= STR_TO_DATE('20201205','%Y%m%d')
AND T1.OrdDtm < STR_TO_DATE('20201206','%Y%m%d')
GROUP BY CASE WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '10' THEN '10시이전주문'
WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '12' THEN '12시이전주문'
WHEN DATE_FORMAT(T1.OrdDtm,'%H') < '17' THEN '17시이전주문'
ELSE '17시이후주문'
END -- 주문시간대구분: GROUP BY에서는 컬럼의 별칭을 사용하지 않도록 주의
ORDER BY 주문시간대구분 ASC;
주문시간대구분 주문시간대별주문건수
-------------- --------------------
10시이전주문 5
12시이전주문 37
17시이전주문 38
아래는 GROUP BY가 아닌 집계함수가 처리된 값에 CASE를 사용하는 예제다. GROUP BY의 기본 원칙은 GROUP BY 절에 컬럼만 SELECT 절에 그대로 사용할 수 있고, 나머지 컬럼은 집계함수 처리해야 한다. CASE는 집계함수 처리된 결과에 사용되고 있으므로 문제 없이 실행된다.
-- [SQL-6-2-5]
-- 집계함수가 처리된 값에 CASE를 사용
SELECT T1.ShopId
,SUM(T1.OrdAmt) OrdAmt
,CASE WHEN SUM(T1.OrdAmt) >= 300000 THEN '30만이상'
WHEN SUM(T1.OrdAmt) >= 200000 THEN '20만이상'
ELSE '20만미만' END AmtDv
FROM startdb.Ord T1
WHERE T1.OrdDtm >= STR_TO_DATE('20230201','%Y%m%d')
AND T1.OrdDtm < STR_TO_DATE('20230301','%Y%m%d')
GROUP BY T1.ShopId
ORDER BY OrdAmt DESC;
ShopId OrdAmt AmtDv
------ ---------- --------
S001 709500.000 30만이상
S200 386500.000 30만이상
S202 348500.000 30만이상
S016 256000.000 20만이상
... 생략 ...
CASE는 ORDER BY 절에도 사용할 수 있다. 아래는 특정 회원의 경우 0으로 치환하고 나머지는 1로 치환해 특정 회원이 무조건 먼저 나오도록 처리한 SQL이다. 나머지 회원은 OrdAmt 순서에 따라 출력 된다.