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 |