인프런 커뮤니티 질문&답변

크루하학님의 프로필 이미지
크루하학

작성한 질문수

[백문이불여일타] 데이터 분석을 위한 중급 SQL

CASE를 활용한 테이블 피봇 리트코드 문제풀이(난이도 상)

SUM() 함수 문의

해결된 질문

작성

·

419

4

안녕하세요-

리트코드 1179 Reformat Department Table 문제 풀이에서 

SUM() 을 왜 사용하는건가요? ㅠ.ㅠ 

선생님 해설 이전에 sum 을 사용하지 않고 코드를 실행했더니 jan 값이 두개가 null 이 출력되면서 오답이라고 떴는데, 

여기서 왜 SUM 함수를 사용해야 제대로된값이 출력되는지 흐름이 이해가안됩니다 ㅠ_ㅠ

답변 5

3

윤선미님의 프로필 이미지
윤선미
지식공유자

CASE 의 속성과 GROUP BY 의 속성을 따로 이해하면 좋을 것 같아요.

CASE는 데이터를 순서대로 조회하면서, IF 조건에 맞는다면 THEN 뒤의 값을 넣고, 그렇지 않으면 ELSE 값을 넣는 역할을 수행해요. 그래서 맨 먼저 아래 쿼리를 실행해서 CASE의 아웃풋이 어떻게 나오는지 확인을 해보셨으면 좋겠어요.

SELECT id 
           , CASE WHEN month = 'Jan' THEN revenue ELSE NULL END AS Jan_Revenue
           , month
           , revenue
FROM DEPARTMENT

부서 id가 어떤 값을 가지든지 상관 없이 month = 'Jan' 이라면 revenue를 넣어주고, 그렇지 않으면 NULL 값을 넣기 때문에 아래와 같이 아웃풋이 나올거예요.

id  Jan_Revenue  month  revenue
1   8000               "Jan"    8000
1   null                  "Feb"    7000
1   null                  "Mar"    6000

여기에서 두번째 그리고 세 번째 행은 부서 id는 1번이지만, month가 "Jan"이 아니기 때문에 7000, 6000인 revenue 값 대신 CASE 문을 통해 null로 표현을 해줬죠. 여기에서 GROUP BY를 id를 기준으로 수행해준다면 어떤 결과가 나올까요?

SELECT id
              , SUM(CASE WHEN month = 'Jan' THEN revenue ELSE NULL END) AS example
FROM DEPARTMENT
GROUP BY id

라고 한다면, 8000, null, null 값들 중 SUM() 함수는 null을 무시하므로 최종적인 값은 아래와 같이 나올거예요

id  example
1   8000

이렇게 CASE 문은 month = 'Jan' 에 해당되지 않는 값들을 null로 표시하고, SUM(), AVG() 같은 집계함수는 null 들을 무시하고 연산을 수행하면서 결국 id, month 조건에 딱 맞는 값만 출력되게 한다고 역할을 나누어서 생각하시면 좋을 것 같네요 :) 답변이 도움이 되었으면 좋겠네요. SQL을 오래 사용하신 분들도 잘 헷갈려하는 파트니까 곰곰히 하나씩 뜯어가면서 쿼리 실행해보고 감을 잡으셨으면해요.
 

0

다른 분의 질문에 죄송합니다. 저도 비슷한 궁금증이 있었는데 덕분에 해결되었어요! 그런데 추가질문이 있어 이렇게 글을 남깁니다 ㅠㅠ

제가 느끼기로는 mysql 자체에서 GROUP BY를 실행할 경우, 한 카테고리에 여러 값이 있을 때 맨 위의 값만 출력하는 경우가 종종 있는 것 같더라고요.

예를 들어 해당 문제에서, id로 GROUP BY를 실행할 경우 단순히 revenue와 month를 출력하라고 명령했을 때 맨 위의 revenue 8000, month Jan만 출력합니다.

SELECT id,revenue,month

FROM DEPARTMENT

GROUP BY id

이 경우 출력되는 값은

{"headers": ["id", "revenue", "month"], "values": [[1, 8000, "Jan"], [2, 9000, "Jan"], [3, 10000, "Feb"]]}

이렇게요.

그러니까 id =1 인 revenue 7000 month Feb나 revenue 6000 month Mar는 아예 출력되지 않는 것 같습니다.

이게 인터프리터 오류인지 혹은 원래 그렇게 설계된 것인지는 모르겠으나, 이러한 현상이 다른 때에도 종종 발생하는 경우를 접했습니다. 

어쨌든 이러한 현상 때문에 SUM과 같은 집계함수를 해야하는 것 같는데, 혹시 맞나요?

아까의 예를 다시 설명하자면, 아까와 같은 코드로 하되 revenue가 아닌 SUM(revenue)를 출력하면 

{"headers": ["id", "SUM(revenue)", "month"], "values": [[1, 21000, "Jan"], [2, 9000, "Jan"], [3, 10000, "Feb"]]}

이렇게 정상적으로 전체 revenue 값이 출력되는 것처럼요.

정리하자면

GROUP BY 함수를 사용할 때 맨 위의 데이터만 출력하는 현상이 존재하고, 집계함수를 사용하여 데이터를 전체적으로(?) 한번 더 읽어주는 것이 맞나요?

또 이걸 작성하면서 생긴 궁금증인데.. 

SELECT문에서

CASE WHEN month='Jan' THEN revenue ELSE NULL END 을 사용함으로써

ID로 GROUP BY된 테이블 속 Jan가 아닌 데이터들의 revenue 값이 다 NULL로 표시하는데요, 

이는 원래의 department 자체를 변화시키는 건 아닌거죠?

raw data를 가져오기만 하는 것이 맞나요?

0

크루하학님의 프로필 이미지
크루하학
질문자

이해하기 쉽게 설명해주셔서 감사합니다 + ㅅ +!!

0

크루하학님의 프로필 이미지
크루하학
질문자

에러가 날때의 SQL 코드 (오답 코드)

SELECT id 
     , CASE WHEN month = 'Jan' THEN revenue ELSE NULL END AS Jan_Revenue
     , CASE WHEN month = 'Feb' THEN revenue ELSE NULL END AS Feb_Revenue
     , CASE WHEN month = 'Mar' THEN revenue ELSE NULL END AS Mar_Revenue
     , CASE WHEN month = 'Apr' THEN revenue ELSE NULL END AS Apr_Revenue
     , CASE WHEN month = 'May' THEN revenue ELSE NULL END AS May_Revenue
     , CASE WHEN month = 'Jun' THEN revenue ELSE NULL END AS Jun_Revenue
     , CASE WHEN month = 'Jul' THEN revenue ELSE NULL END AS Jul_Revenue
     , CASE WHEN month = 'Aug' THEN revenue ELSE NULL END AS Aug_Revenue
     , CASE WHEN month = 'Sep' THEN revenue ELSE NULL END AS Sep_Revenue
     , CASE WHEN month = 'Oct' THEN revenue ELSE NULL END AS Oct_Revenue
     , CASE WHEN month = 'Nov' THEN revenue ELSE NULL END AS Nov_Revenue
     , CASE WHEN month = 'Dec' THEN revenue ELSE NULL END AS Dec_Revenue
FROM DEPARTMENT
GROUP BY id

----- 위 SQL문 Output

{
"headers": ["id", "Jan_Revenue", "Feb_Revenue", "Mar_Revenue", "Apr_Revenue", "May_Revenue", "Jun_Revenue", "Jul_Revenue", "Aug_Revenue", "Sep_Revenue", "Oct_Revenue", "Nov_Revenue", "Dec_Revenue"],

"values": [
[1, 8000, null, null, null, null, null, null, null, null, null, null, null],
[2, 9000, null, null, null, null, null, null, null, null, null, null, null],
[3, null, 10000, null, null, null, null, null, null, null, null, null, null]
]}

-------

------ Expected

{
"headers": ["id", "Jan_Revenue", "Feb_Revenue", "Mar_Revenue", "Apr_Revenue", "May_Revenue", "Jun_Revenue", "Jul_Revenue", "Aug_Revenue", "Sep_Revenue", "Oct_Revenue", "Nov_Revenue", "Dec_Revenue"],
"values": [
[1, 8000,
7000, 6000, null, null, null, null, null, null, null, null, null],
[2, 9000, null, null, null, null, null, null, null, null, null, null, null],
[3, null, 10000, null, null, null, null, null, null, null, null, null, null]]
}


위 결과물처럼  1번 Row 의 revenue 2번, 3번 값이 7000, 6000 이 들어가는게 아닌 
null 이 들어갑니다,

해서 선생님 해설대로 SUM 으로 감싸주었을때는 null 이 아니라 7000,6000 이 출력되면서 정답처리 되는데요!

여기서 어려운것이..
저는 시나리오를 아래처럼 생각했는데, 


Table의 모든 행을
 CASE WHEN month = 'Jan' THEN revenue ELSE NULL END AS Jan_Revenue 문으로 돌면서,
  month 가 Jan 인 Revenue 값을 가져오기 때문에, 별도의 SUM 함수가 없어도 알아서 7000, 6000 의 값이 들어갈것이다

그런데 첫번째 값인 8000 을 제외하고는 왜 null이 들어가고, 
이걸 해결하기 위해 왜 SUM(), MAX() 등의 함수로 처리해야 하는지 이해가 어렵습니다 ㅠ


-- 이하 문제에서의 Table

Department table:
+------+---------+-------+
| id   | revenue | month |
+------+---------+-------+
| 1    | 8000    | Jan   |
| 2    | 9000    | Jan   |
| 3    | 10000   | Feb   |
| 1    | 7000    | Feb   |
| 1    | 6000    | Mar   |
+------+---------+-------+

0

윤선미님의 프로필 이미지
윤선미
지식공유자

가빈님, 안녕하세요! 테이블 피봇 문제가 원래 좀 어려워요ㅎㅎ

근데 제가 가빈님이 어떤 코드를 작성했을 때에 어떤 에러가 났는지 알 수가 없어서 혹시 에러가 날 때의 SQL 코드와, 결과값을 올려주실 수 있을까요? 그리고 그 코드가 어떤 결과를 출력할거라고 예상하셨는지 예상 output도 같이 적어주시면 좋겠어요.

크루하학님의 프로필 이미지
크루하학

작성한 질문수

질문하기