SQL GROUP BY 사용법: 집계 함수와 함께 쉽게 배우기
SQL GROUP BY 사용법이란
SQL GROUP BY 사용법의 핵심은 "같은 값을 가진 행들을 하나의 그룹으로 묶어, 그룹별로 집계한다"는 것입니다. 예를 들어 주문 데이터를 고객별로 묶어 고객마다 총 주문 금액을 구하거나, 카테고리별 상품 개수를 세는 식입니다. GROUP BY는 거의 항상 집계 함수(COUNT, SUM, AVG, MAX, MIN)와 짝을 이룹니다.
예제 테이블은 다음과 같습니다.
-- orders
id | customer | category | amount
1 | 김철수 | 식품 | 5000
2 | 김철수 | 도서 | 3000
3 | 이영희 | 식품 | 7000
4 | 이영희 | 식품 | 2000
5 | 박민수 | 도서 | 1000기본 문법과 집계 함수
고객별 주문 건수와 총액을 구해 봅시다.
SELECT customer,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer;
-- 결과
김철수 | 2 | 8000
이영희 | 2 | 9000
박민수 | 1 | 1000주요 집계 함수는 다음과 같습니다. COUNT(*)는 행 개수, SUM은 합계, AVG는 평균, MAX/MIN은 최댓값/최솟값입니다. 참고로 COUNT(컬럼)은 해당 컬럼이 NULL이 아닌 행만 셉니다.
여러 컬럼으로 그룹화
GROUP BY에는 컬럼을 여러 개 지정할 수 있습니다. 이때는 지정한 컬럼들의 조합이 같은 행끼리 묶입니다.
SELECT customer, category, SUM(amount) AS total
FROM orders
GROUP BY customer, category;
-- 결과 (customer + category 조합별)
김철수 | 식품 | 5000
김철수 | 도서 | 3000
이영희 | 식품 | 9000 -- 7000 + 2000
박민수 | 도서 | 1000GROUP BY + HAVING + ORDER BY
그룹화한 결과에 조건을 걸 때는 WHERE가 아니라 HAVING을 씁니다. WHERE는 그룹화 전 행을, HAVING은 그룹화 후 집계 결과를 거릅니다.
SELECT customer, SUM(amount) AS total
FROM orders
WHERE amount >= 1000 -- 그룹화 전 행 필터
GROUP BY customer
HAVING SUM(amount) >= 5000 -- 그룹화 후 집계 필터
ORDER BY total DESC; -- 총액 내림차순 정렬
-- 결과
이영희 | 9000
김철수 | 8000작성 순서는 SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY로 외워 두면 편합니다.
GROUP BY 관련 절 정리표
| 절 | 역할 | 집계 함수 |
|---|---|---|
| WHERE | 그룹화 전 행 필터 | 사용 불가 |
| GROUP BY | 행을 그룹으로 묶음 | - |
| HAVING | 그룹화 후 결과 필터 | 사용 가능 |
| ORDER BY | 최종 결과 정렬 | 사용 가능 |
실전 팁
SELECT 절에는 두 종류만 올 수 있습니다. (1) GROUP BY에 명시한 컬럼, (2) 집계 함수입니다. 이 규칙을 지키면 "그룹당 값이 하나로 정해지지 않는" 모호함을 피할 수 있습니다. 또한 자주 그룹화하는 컬럼에 인덱스가 있으면 정렬·그룹화 비용이 줄어 성능에 도움이 됩니다.
흔한 실수
1. 집계되지 않은 컬럼을 SELECT에 넣기. SELECT customer, category FROM orders GROUP BY customer는 표준 SQL에서 오류입니다. category는 한 고객 안에서 여러 값일 수 있어 어떤 값을 보여줄지 모호하기 때문입니다. 해당 컬럼을 GROUP BY에 추가하거나 집계 함수로 감싸야 합니다. (MySQL 일부 설정은 임의 값을 반환하지만 신뢰하지 마세요.)
2. WHERE에 집계 조건 쓰기. WHERE SUM(amount) > 5000은 오류입니다. 집계 결과 조건은 HAVING으로 옮겨야 합니다.
자주 묻는 질문
Q1. COUNT(*)와 COUNT(컬럼)의 차이는?
COUNT(*)는 NULL 포함 모든 행을 세고, COUNT(컬럼)은 해당 컬럼이 NULL이 아닌 행만 셉니다. 중복을 빼고 세려면 COUNT(DISTINCT 컬럼)을 씁니다.
Q2. GROUP BY 없이 집계 함수만 쓸 수 있나요?
가능합니다. GROUP BY가 없으면 전체 행이 하나의 그룹으로 취급됩니다. SELECT COUNT(*), AVG(amount) FROM orders는 전체에 대한 집계를 반환합니다.
Q3. 그룹별 합계와 전체 합계를 함께 보고 싶어요.
GROUP BY customer WITH ROLLUP(MySQL) 또는 GROUP BY ROLLUP(customer)(PostgreSQL, Oracle)를 쓰면 소계와 총계를 한 번에 얻을 수 있습니다.