일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- leetcode
- 편향-분산 교환
- programmers
- conflict
- 선형 모형
- mysql
- merge
- coding
- PYTHON
- hackerrank
- window function
- 깃헙협업
- 교차 엔트로피
- 코딩공부
- Git
- branch
- HTML
- 버전충돌
- RLIKE
- sql
- 클라우드컴퓨팅
- full request
- 온라인협업
- CSS
- L1정규화
- early stopping
- elastic net
- AWS
- L2정규화
- github
- Today
- Total
Im between cherry
[MySQL] table pivot을 하며 깨달은 CASE()과 GROUP BY()의 속성 본문
leetcode.com/problems/reformat-department-table/
이 문제를 풀 때마다 SUM()을 쓰는 이유에 대해 헷갈렸다!
선미님께서 CASE()와 GROUP BY()의 속성을 생각한다면 조금 더 쉽게 이해할 수 있을 거라고 하셔서, 다시 정리하며 풀어 보았다!
일단, 코드부터 보면 아래와 같다.
SELECT id
, SUM(CASE WHEN month = 'Jan' THEN revenue ELSE NULL END) AS Jan_Revenue
, SUM(CASE WHEN month = 'Feb' THEN revenue ELSE NULL END) AS Feb_Revenue
, SUM(CASE WHEN month = 'Mar' THEN revenue ELSE NULL END) AS Mar_Revenue
, SUM(CASE WHEN month = 'Apr' THEN revenue ELSE NULL END) AS Apr_Revenue
, SUM(CASE WHEN month = 'May' THEN revenue ELSE NULL END) AS May_Revenue
, SUM(CASE WHEN month = 'Jun' THEN revenue ELSE NULL END) AS Jun_Revenue
, SUM(CASE WHEN month = 'Jul' THEN revenue ELSE NULL END) AS Jul_Revenue
, SUM(CASE WHEN month = 'Aug' THEN revenue ELSE NULL END) AS Aug_Revenue
, SUM(CASE WHEN month = 'Sep' THEN revenue ELSE NULL END) AS Sep_Revenue
, SUM(CASE WHEN month = 'Oct' THEN revenue ELSE NULL END) AS Oct_Revenue
, SUM(CASE WHEN month = 'Nov' THEN revenue ELSE NULL END) AS Nov_Revenue
, SUM(CASE WHEN month = 'Dec' THEN revenue ELSE NULL END) AS Dec_Revenue
FROM Department
GROUP BY id
월별 수익을 id별로 알 수 있는 테이블을 피보팅해야 했는데,
CASE문에 왜 `SUM`을 써야하는지 너무나 헷갈렸다.
CASE()의 속성
`CASE WHEN ~ THEN ~ ELSE ~ END` : 데이터를 순서대로 조회하면서, WHEN 조건에 맞는다면 THEN 뒤의 값을 넣고, 그렇지 않으면 ELSE 값을 넣는 역할을 한다.
아래 쿼리를 실행해서 CASE문에 따라 Jan_Revenue가 어떻게 나오는지 확인해보자.
SELECT id
, month
, revenue
, CASE WHEN month = 'Jan' THEN revenue ELSE NULL END AS Jan_Revenue
FROM DEPARTMENT
id, month, revenue를 차례대로 출력하고,
CASE문에 따라 month = 'Jan' 이라면 Jan_Revenue에 revenue의 값을, 그렇지 않으면 NULL 값을 출력해준다.
---+--------+------------+--------------
id month revenue Jan_Revenue
---+--------+------------+--------------
1 "Jan" 8000 8000
1 "Feb" 7000 NULL
1 "Mar" 6000 NULL
2 "Jan" 9000 9000
3 "Feb" 10000 NULL
---+--------+------------+--------------
id가 1인 것만 봤을 때
-> id가 1인 첫번째 행은 month가 "Jan"이기 때문에 revenue의 8000을 그대로 Jan_Revenue에 넣어준다.
-> id가 1인 두번째,세 번째 행은 month가 "Jan"이 아니기 때문에 7000, 6000인 revenue 값 대신 CASE 문을 통해 NULL로 나온다.
그럼 Feb_Revenue도 추가해서 어떻게 나오는지 확인해보자.
SELECT id
, month
, revenue
, CASE WHEN month = 'Jan' THEN revenue ELSE NULL END AS Jan_Revenue
, CASE WHEN month = 'Feb' THEN revenue ELSE NULL END AS Feb_Revenue
FROM DEPARTMENT
첫번째 CASE문에 따라 month = 'Jan' 이라면 Jan_Revenue에 revenue의 값을, 그렇지 않으면 NULL 값을 출력,
두번째 CASE문에 따라 month = 'Feb' 이라면 Feb_Revenue에 revenue의 값을, 그렇지 않으면 NULL 값을 출력해준다.
---+--------+------------+---------------+----------------
id month revenue Jan_Revenue Feb_Revenue
---+--------+------------+---------------+----------------
1 "Jan" 8000 8000 NULL
1 "Feb" 7000 NULL 7000
1 "Mar" 6000 NULL NULL
2 "Jan" 9000 9000 NULL
3 "Feb" 10000 NULL 10000
---+--------+------------+---------------+----------------
id가 1인 것만 봤을 때
-> id가 1인 첫번째 행은 month가 "Feb"가 아니기 때문에 NULL값을 Feb_Revenue에 넣어준다
-> id가 1인 두번째 행은 month가 "Feb"기 때문에 7000인 revenue 값을 그대로 Feb_Revenue에 넣어준다.
GROUP BY()의 속성
여기에 CASE문에 SUM()을 걸어주지 않고, GROUP BY를 id 기준으로 수행해주면,
SELECT id
, month
, revenue
, CASE WHEN month = 'Jan' THEN revenue ELSE NULL END AS Jan_revenue
, CASE WHEN month = 'Feb' THEN revenue ELSE NULL END AS Feb_Revenue
FROM DEPARTMENT
GROUP BY id
---+--------+------------+---------------+---------------
id month revenue Jan_Revenue Feb_Revenue
---+--------+------------+---------------+---------------
1 "Jan" 8000 8000 NULL
2 "Jan" 9000 9000 NULL
3 "Feb" 10000 NULL 10000
---+--------+------------+---------------+---------------
-> id가 1이고, month="Jan"일 때, revenue인 8000을 Jan_Revenue에 넣고, 그 외에는(Feb_Revenue에는) NULL이 들어가게 된다.
-> 더하는 게 아니므로 그대로 출력한다.
따라서, 월별 수익을 id별로 보려면 SUM을 써서 합쳐줘야 한다.
SUM()을 해주면,
SELECT id
, month
, revenue
, SUM(CASE WHEN month = 'Jan' THEN revenue ELSE NULL END) AS Jan_revenue
, SUM(CASE WHEN month = 'Feb' THEN revenue ELSE NULL END) AS Feb_Revenue
FROM DEPARTMENT
GROUP BY id
---+--------+------------+---------------+---------------
id month revenue Jan_Revenue Feb_Revenue
---+--------+------------+---------------+---------------
1 "Jan" 8000 8000 7000
2 "Jan" 9000 9000 NULL
3 "Feb" 10000 NULL 10000
---+--------+------------+---------------+---------------
-> id가 1이고, month="Jan"일 때, revenue인 8000을 Jan_Revenue에 넣고, 그 외에는(Feb_Revenue에는) NULL이 들어가게 된다.
-> 그리고 id가 1인 것의 Jan_Revenue 값 8000, NULL, NULL을 다 더해주고, id가 1인 것의 Feb_Revenue값 NULL, 7000, NULL을 다 더해준다.
-> SUM() 함수는 NULL을 무시하므로 Jan_Revenue의 최종값은 8000, Feb_Revenue의 최종값은 7000이 된다.
+ SUM()이 아닌 AVG()같은 집계함수를 써도 NULL은 무시하고 연산해주므로 괜찮다.
다시는 휘발되지 말자 나의 작고 소중한 SQL 지식아..
'데이터분석 > SQL' 카테고리의 다른 글
[MySQL] DATE_ADD()/DATE_SUB() 함수, INTERVAL (0) | 2020.11.07 |
---|---|
SQL | 윈도우함수(window function)란 무엇인가? (0) | 2020.10.09 |
MySQL | Subquery (0) | 2020.10.08 |
MySQL | ROW_NUMBER(), RANK(), DENSE_RANK() 윈도우 함수 (0) | 2020.08.30 |
MySQL | LEAD, LAG 윈도우 함수 (0) | 2020.08.30 |