GROUP BY절은 SELECT문에서 특정 컬럼(또는 특정 컬럼 내 데이터를 가공해서)의 데이터를 기준으로 그룹핑을 하여 그룹핑한 데이터 기준으로 집계함수를 사용할 때 이용합니다.
to_char(컬럼이름, 'YYYY-MM')
식으로 특정 년월 단위로 가공하여 그룹핑 할 수 있습니다.💡
WHERE
vsHAVING
- WHERE절의 경우 GROUP BY로 그룹핑 하기전에 실행되기 때문에, 그룹핑한 데이터 기준으로 조건을 주기 위해서는 HAVING 절을 이용해야합니다.
- HAVING 절로도 WHERE절 처럼 그룹핑한 결과와 상관없이 이용할 수 있긴하지만, HAVING 절의 경우 인덱스를 활용하는데 한계가 있기 때문에 가능한 그룹핑과 상관없는 조건은 WHERE절에서 사용하고, HAVING절은 그룹한 후 조건 체크가 필요할 때만 사용하는게 옳습니다.
-- 사용법
SELECT 컬럼1, 컬럼2,,,
FROM 테이블명
[WHERE 조건절]
GROUP BY 기준컬럼1, 기준컬럼2,,,
[HAVING 조건절]
[ORDER BY 컬럼,,,]
[LIMIT [시작 인덱스, ] 개수]
;
-- 사용예시
SELECT
memberID, SUM(orderAmount)
FROM tbl_orderinfo
GROUP BY memberId
;
GROUP BY
vs OVER(PARTITION BY 컬럼)
GROUP BY 컬럼
: 해당 SELECT문 전체를 지정된 열 내 동일한 데이터끼리 그룹화합니다.OVER(PARTITION BY 컬럼)
: 집계함수와 함께 사용하는 구문으로, 지정된 열 내 동일한 데이터끼리 그룹화 하는 구문 입니다.GROUP BY
의 경우 해당 SELECT문 결과셋 자체에 대해 구룹핑하여 최종 결과셋을 출력하는 반면, OVER(PARTITION BY 컬럼)
은 해당 열에 대해서만 구룹핑한 결과만을 출력하기 때문에 집계함수를 쓸 때마다 해당 구문을 작성해줘야합니다.GROUP BY
의 경우 그룹핑한 데이터를 기준으로 한 행의 데이터만 표시하지만, OVER(PARTITION BY 컬럼)
은 데이터 개수만큼 전부 동일한 데이터를 표시하게 됩니다.-- GROUP BY VS OVER(PARTITION BY) 비교
# GROUP BY
SELECT
memberId
, SUM(orderAmount)
, AVG(orderAmount)
FROM tbl_orderinfo
GROUP BY memberID
;
# OVER(PARTITION BY)
SELECT
memberId
, SUM(orderAmount) OVER (PARTITION BY memberId) AS total
, AVG(orderAmount) OVER (PARTITION BY memberId) AS total_AVG
FROM tbl_orderinfo
;
💡
OVER(PARTITION BY 컬럼)
으로도 GROUP BY처럼 결과셋을 출력할 수 있다?
OVER(PARTITION BY)
구문으로 작성된 경우에도DISTINCT
키워드를 추가하여, 중복된 행을 제거하면 GROUP BY를 사용했을 때와 같은 결과셋을 반환 받을 수 있습니다.# 그냥 OVER(PARTITION BY 컬럼) SELECT memberId , SUM(orderAmount) OVER (PARTITION BY memberId) AS total , AVG(orderAmount) OVER (PARTITION BY memberId) AS total_AVG FROM tbl_orderinfo ; # DISTINCT + OVER (PARTITION BY 컬럼) SELECT DISTINCT memberId , SUM(orderAmount) OVER (PARTITION BY memberId) AS total , AVG(orderAmount) OVER (PARTITION BY memberId) AS total_AVG FROM tbl_orderinfo ;
집계함수는 GROUP BY없이 그냥도 사용할 수 있지만 특정 그룹별 집계를 조회하기 위해 GROUP BY절과 함께 자주 사용 됩니다.
아래는 자주 사용되는 집계함수를 확인해보겠습니다!
SUM()
인자로 넣은 컬럼을 모두 더하여 합계를 반환해주는 집계함수 입니다.
GROUP BY절과 함께 사용 시 그룹핑한 그룹 별 합계를 반환해 줍니다.
-- 사용법
SELECT SUM(컬럼) FROM 테이블;
-- 사용예시
# GROUP BY 없이 사용
SELECT SUM(orderAmount) # 해당 테이블 내 orderAmount 열 모든 데이터를 합한 값 출력됨.
FROM tbl_orderinfo
;
# GROUP BY와 함께 사용
SELECT
memberId
, SUM(orderAmount)
FROM tbl_orderinfo
GROUP BY memberId
;
AVG()
인자로 넣은 컬럼의 평균을 반환해주는 집계함수 입니다.
GROUP BY절과 함께 사용 시 그룹핑한 그룹 별 평균 반환해 줍니다.
-- 사용법
SELECT AVG(컬럼) FROM 테이블;
-- 사용예시
# GROUP BY 없이 사용
SELECT AVG(orderAmount)
FROM tbl_orderinfo
;
# GROUP BY와 함께 사용
SELECT
memberId
, AVG(orderAmount)
FROM tbl_orderinfo
GROUP BY memberId
;
MAX()
/ MIN()
인자로 넣은 컬럼에서 가장 큰 값(MAX), 가장 작은 값(MIN)을 반환해주는 집계함수 입니다.
GROUP BY절과 함께 사용 시 그룹핑한 그룹 별 가장 큰 값(MAX), 가장 작은 값(MIN)을 반환해 줍니다.
-- 사용법
SELECT MAX(컬럼), MIN(컬럼) FROM 테이블;
-- 사용예시
# GROUP BY 없이 사용
SELECT
MAX(orderAmount)
, MIN(orderAmount)
FROM tbl_orderinfo
;
# GROUP BY와 함께 사용
SELECT
memberId
, MAX(orderAmount)
, MIN(orderAmount)
FROM tbl_orderinfo
GROUP BY memberId
;
COUNT()
인자로 넣은 컬럼의 데이터 개수(행 개수)를 반환해주는 집계함수 입니다.
GROUP BY절과 함께 사용 시 그룹핑한 그룹 별 데이터 개수(행 개수)를 반환해 줍니다.
-- 사용법
SELECT COUNT(컬럼) FROM 테이블;
-- 사용예시
# GROUP BY 없이 사용
SELECT COUNT(orderAmount)
FROM tbl_orderinfo
;
# GROUP BY와 함께 사용
SELECT
memberId
, COUNT(orderAmount)
FROM tbl_orderinfo
GROUP BY memberId
;
WITH ROLLUP절
WITH ROLLUP
절의 경우 GROUP BY절에 사용할 수 있으며 그룹핑 된 그룹별 총 합계를 만들어주는 구문 입니다.
-- 사용법
SELECT 컬럼1, 컬럼2,,,
FROM 테이블명
[WHERE 조건절]
GROUP BY 기준컬럼1, 기준컬럼2,,, WITH ROLLUP
[HAVING 조건절]
[ORDER BY 컬럼,,,]
[LIMIT [시작 인덱스, ] 개수]
;
-- 사용예시
# 1개의 조건으로 그룹 후 WITH ROLLUP 사용
SELECT
to_char(from_date, 'YYYY')
, SUM(salary) AS sum_salary
FROM salaries
WHERE from_date BETWEEN '2000-01-01' AND '2002-12-31'
GROUP BY to_char(from_date, 'YYYY') WITH ROLLUP;
# 2개의 조건으로 그룹 후 WITH ROLLUP 사용
SELECT
to_char(A.from_date, 'YYYY') AS 'YEAR'
, C.dept_no, SUM(A.salary) AS sum_salary
FROM salaries AS A
INNER JOIN ( # dept_emp에서 부서가 여러개인 사원들이 있어서 한 건만 나올 수 있도록 인라인 뷰 작성
SELECT emp_no, dept_no
FROM dept_emp
GROUP BY emp_no
) AS B ON B.emp_no = A.emp_no
INNER JOIN departments AS C ON C.dept_no = B.dept_no
WHERE A.from_date BETWEEN '2000-01-01' AND '2002-12-31'
GROUP BY to_char(A.from_date, 'YYYY'), C.dept_no WITH ROLLUP;
💡 실습 : 다차원 피벗 테이블 만들어보기
- 요청사항
salary 테이블 에서 직원번호가 10001 ~ 10020인 직원들의 1990년 ~ 2002년 까지의 연봉 평균 데이터를 주세요
- 풀이
SELECT emp_no , AVG(case YEAR(from_date) when 1990 then salary ELSE 0 END) AS '1990년' , AVG(case YEAR(from_date) when 1991 then salary ELSE 0 END) AS '1991년' , AVG(case YEAR(from_date) when 1992 then salary ELSE 0 END) AS '1992년' , AVG(case YEAR(from_date) when 1993 then salary ELSE 0 END) AS '1993년' , AVG(case YEAR(from_date) when 1994 then salary ELSE 0 END) AS '1994년' , AVG(case YEAR(from_date) when 1995 then salary ELSE 0 END) AS '1995년' , AVG(case YEAR(from_date) when 1996 then salary ELSE 0 END) AS '1996년' , AVG(case YEAR(from_date) when 1997 then salary ELSE 0 END) AS '1997년' , AVG(case YEAR(from_date) when 1998 then salary ELSE 0 END) AS '1998년' , AVG(case YEAR(from_date) when 1999 then salary ELSE 0 END) AS '1999년' , AVG(case YEAR(from_date) when 2000 then salary ELSE 0 END) AS '2000년' , AVG(case YEAR(from_date) when 2001 then salary ELSE 0 END) AS '2001년' , AVG(case YEAR(from_date) when 2002 then salary ELSE 0 END) AS '2002년' FROM salaries WHERE (from_date BETWEEN '1990-01-01' AND '2002-12-31') AND emp_no <= 10020 GROUP BY emp_no WITH ROLLUP ;
- 결과
MariaDB로 따라 하며 배우는 SQL프로그래밍 데이터베이스 기초에서 실무까지 - 나익수, 서연경 지음
위 책을 공부하며 작성하고 있습니다!