데이터 & AI/MySQL

[MySQL] GROUP BY,HAVING,WITH ROLLUP,GROUPING

뭉실뭉실뜬구름 2023. 4. 20. 16:56
728x90
1 codeit@naver.com 28 m 178.2 70 1992-01-03 2019-03-26 서울특별시 중구 삼일대로 343 103호
2 korin02@google.com 29 m 165.7 67.3 1992-08-13 2019-02-27 서울특별시 중구 세종대로 110 502호
3 cowboy@codeit.kr 31 m   70.2 1990-01-03 2019-01-05 경기도 고양시 일산서구 고양대로 633 204동 203호
4 get_flower@naver.com -10 f 183.5 72 1975-03-12 2018-11-29  
5 taehos@hanmail.net 27 m 181.3 70 1992-09-02 2017-03-14 제주 제주시 문연로 6 102동 1105호
6 iamstylish@naver.com 300 f 172.2   1989-01-03 2012-11-15 안드로메다 128행성
7 captainGoGo03@koreauniv.com 28 m 195.2 66 1992-03-13 2014-03-18 전라남도 순천시 왕지3길 60 112동 107호
8 sungsos@naver.com 36 f 167.7 66.2 1992-01-03 2017-03-20 경기도 부천시 평천로 679 101동 101호

 

 

 

Q. 자료를 특정 기준에 따라 그룹별로 나누고 싶으면 어떻게 해야할까? 

A. 그럴 떄는 GROUP BY절을 사용하면 돼. 예를 들어 성별을 기준으로 그룹을 만들고 싶으면 이렇게 만들면 돼

SELECT gender FROM copang_main.member GROUP BY gender;
m
f

Q. 잉 하지만 저거는 옛날에 DISTINCT함수랑 결과 값이 똑같은데?? 그냥 종류만 알려주잖아...

A. 아냐 이거는 그루핑을 했기 떄문에 저 안에 각 성별에 해당하는 수가 들어있어 이제 저거를 우리는 COUNT 함수를 통해

표현하면 돼. 밑에 count,avg,min 함수들을 집계 함수라고 하는데 그루핑을 통해서 만들어진 각 그룹의 수치적인 특징을 구해주는 함수야.

SELECT gender,COUNT(*), AVG(height),MIN(weight) FROM copang_main.member GROUP BY gender;

gender                      COUNT(*)                      AVG(height)                                                    MIN(weight)

m 15 176.55 56
f 9 173.7 48.2

Q. 엄...그렇다면 주소를 이용해서도 그루핑이 가능할까?

A. 그럼그럼 단 예전에 배운 SUBSTRING 함수를 이용해서 주소 앞에 2글자만 추출해서 그루핑을 해주면 돼

SELECT SUBSTRING(address,1,2) AS region ,COUNT(*) FROM member GROUP BY SUBSTRING(address,1,2)
서울 5
경기 6
  4
제주 1
안드 1
전라 1
인천 2
강원 2
부산 1
어린 1

Q. 그럼 그루핑을 2개 이상의 조건으로도 할 수 있나요?

A. 그럼그럼 저기에 만약 같은 지역에서 성별에 따라 나누고 싶으면 그냥 바로 옆에 gender컬럼을 추가해주면 된단다.

SELECT SUBSTRING(address,1,2) AS region,gender FROM member 
GROUP BY SUBSTRING(address,1,2),gender 
ORDER BY region ASC,gender DESC;
  m
  f
강원 m
경기 m
경기 f
부산 f
서울 m
서울 f
안드 f
어린 m
인천 m
인천 f
전라 m
제주 m

Q. NULL값 지우기

A. HAVING 함수 사용 : having은 ~을 가지고 있는 이라는 뜻으로 조건문 같은 것이다.  WHERE절과 비슷한 기능을 가지고 있지만 GROUP BY절에서는 WHERE을 쓸 수 없다. 이 둘의 목적이 다르기 때문이다. WHERE은 테이블에서 맨 처음 로우들을 조회할때 조건을 설정하기 위한 구문이지만 HAVING은 이미 선택된 그룹들 중에서 다시 필터링할 때 쓰는 구문이다.


SELECT 
SUBSTRING(address,1,2) AS region, 
gender,
COUNT(*) 
FROM member GROUP BY SUBSTRING(address,1,2),gender HAVING region IS NOT NULL ORDER BY region ASC,gender DESC;
강원 m 2
경기 m 3
경기 f 3
부산 f 1
서울 m 4
서울 f 1
안드 f 1
어린 m 1
인천 m 1
인천 f 1
전라 m 1
제주 m 1

GROUP BY절 사용시 반드시 지켜야 하는 규칙

SELECT절에는 GROUP BY 뒤에서 사용한 컬럼들 또는 COUNT(),MAX()등과 같은 집계함수만 사용가능

위에 표를 봤을 때 하나의 로우는 단 하나의 로우를 의미하지 않는다. 저 안의 여러 개의 로우가 존재하고 있다. 그렇기 때문에 만약 그루핑 하지 않은 로우를 SELECT 할 경우 예를 들어 age를 뽑는 경우 각 로우에서 어떤 age 로우를 가져와야 할지 모르기 때문에 에러가 발생한다. 하지만 그래서 집계함수는 가능하다. 즉 AVG(age)는 뒤에서 age를 그루핑하지 않아도 특정 하나의 로우를 필요로 하지 않고 모든 로우를 계산해서 결과를 출력하기 때문에 상관 없이 사용가능 하다.

 

 

 

GROUP BY 심화: WITH ROLLUP

ROLLUP: 말다, 소매를 걷어올리다라는 뜻으로 세부 그룹들을 좀더 큰 단위의 그룹으로 중간중간에 합쳐준다. 아래 표를 보면 그루핑절 gender에 WITH ROLLUP을 붙여줬더니 표에 각 지역별로 성별은 NULL값이고 각 성별 인원 수를 합한 새로운 row가 완성 됐다.

SELECT 
	SUBTRING(address,1,2) AS region, 
	gender, 
	COUNT(*) 
FROM member 
GROUP BY 
	SUBTRING(address,1,2),
	gender 
WITH ROLLUP 
HAVING region IS NOT NULL 
ORDER BY 
	region ASC,
	gender DESC;
강원 m 2
강원   2
경기 m 3
경기 f 3
경기   6
부산 f 1
부산   1
서울 m 4
서울 f 1
서울   5
안드 f 1
안드   1
어린 m 1
어린   1
인천 m 1
인천 f 1
인천   2
전라 m 1
전라   1
제주 m 1
제주   1

* GROUP BY 뒤 기준들의 순서에 따라 WITH ROLLUP의 결과도 달라진다.

* 만약 부분 총계를 나타내기 위해 쓰인 NULL가 원래 NULL값이 같이 있는 경우 이 둘은 GROUPING()함수를

이용해서 해결할 수 있다. 밑에 표를 봤을때 그루핑한 컬럼이 추가됐다. 1이면 부분 총계를 나타내기 위한 NULL

0이면 원래 NULL이었던 것이다.

SELECT YEAR(sign_up_day) AS s_year,gender,SUBSTRING(address,1,2) AS region,COUNT(*)
FROM member
GROUP BY YEAR(sign_up_day),gender,SUBSTRING(address,1,2) WITH ROLLUP
ORDER BY s_year DESC;





SELECT YEAR(sign_up_day) AS s_year,gender,SUBSTRING(address,1,2) AS region,
GROUPING(YEAR(sign_up_day)),GROUPING(gender),GROUPING(SUBSTRING(address,1,2)),COUNT(*)
FROM member
GROUP BY YEAR(sign_up_day),gender,SUBSTRING(address,1,2) WITH ROLLUP
ORDER BY s_year DESC;
2019 m   1
2019 m 경기 1
2019 m 서울 3
2019 m   5
2019     5
2018 f   2
2018 f 부산 1
2018 f 서울 1
2018 f   4
2018 m 인천 1
2018 m   1
2018     5
2017 f 경기 3
2017 f   3
2017 m 강원 1
2019 m   0 0 0 1
2019 m 경기 0 0 0 1
2019 m 서울 0 0 0 3
2019 m   0 0 1 5
2019     0 1 1 5
2018 f   0 0 0 2
2018 f 부산 0 0 0 1
2018 f 서울 0 0 0 1
2018 f   0 0 1 4
2018 m 인천 0 0 0 1
2018 m   0 0 1 1
2018     0 1 1 5
2017 f 경기 0 0 0 3
2017 f   0 0 1 3
728x90