핵심 요약
GROUP BY는 같은 값을 가진 행들을 묶어서 하나로 요약한다. "카테고리별 상품 수", "사용자별 주문 합계"처럼 그룹 단위로 COUNT·SUM·AVG 같은 집계 함수를 적용한다. 헷갈리는 건 WHERE(그룹 전 필터)와 HAVING(그룹 후 필터)의 차이다.
1. 기본 형태
-- 카테고리별 상품 개수와 평균 가격
SELECT category, COUNT(*) AS cnt, AVG(price) AS avg_price
FROM products
GROUP BY category;
GROUP BY category로 카테고리마다 묶고, 각 그룹에 COUNT·AVG를 적용한다. 결과는 카테고리 하나당 한 행이다.
2. 주요 집계 함수
| 함수 | 의미 |
|---|---|
| COUNT(*) | 행 수 |
| SUM(x) | 합계 |
| AVG(x) | 평균 |
| MAX/MIN(x) | 최대/최소 |
3. WHERE vs HAVING — 핵심
SELECT category, COUNT(*) AS cnt
FROM products
WHERE price >= 1000 -- ① 그룹 전: 개별 행 필터
GROUP BY category
HAVING COUNT(*) >= 5; -- ② 그룹 후: 집계 결과 필터
- WHERE — 그룹으로 묶기 전에 개별 행을 거른다(집계 함수 못 씀)
- HAVING — 묶고 집계한 후에 그룹을 거른다(집계 함수 씀)
"1000원 이상 상품만 대상으로, 그런 상품이 5개 이상인 카테고리"가 위 쿼리다.
4. 흔한 함정
- SELECT에 집계 안 한 컬럼 —
GROUP BY에 없는 일반 컬럼을 SELECT하면 에러(또는 임의값). 그룹 키이거나 집계여야 한다. - WHERE에서 집계 함수 사용 —
WHERE COUNT(*) > 5는 에러. 집계 조건은 HAVING으로. - NULL 처리 —
COUNT(column)은 NULL을 세지 않는다. 전체 행은COUNT(*).
자주 묻는 질문
WHERE와 HAVING을 언제 구분해서 쓰나요?
개별 행을 거르는 조건은 WHERE, 그룹으로 묶어 집계한 결과를 거르는 조건은 HAVING입니다. 예를 들어 "비싼 상품만 대상으로"는 WHERE, "상품이 N개 이상인 그룹만"은 HAVING입니다. 가능하면 WHERE로 먼저 걸러야 집계 대상이 줄어 빠릅니다.
GROUP BY에 없는 컬럼을 왜 SELECT 못 하나요?
그룹이 여러 행을 하나로 묶는데, 묶이지 않은 일반 컬럼은 그룹 안에서 값이 여러 개라 무엇을 보여줄지 모호하기 때문입니다. 그래서 그룹 키이거나 집계 함수(MAX 등)로 하나의 값으로 만들어야 합니다.
COUNT(*)와 COUNT(컬럼)은 다른가요?
네. COUNT(*)는 NULL 포함 전체 행 수이고, COUNT(컬럼)은 그 컬럼이 NULL이 아닌 행만 셉니다. "값이 있는 것만" 세고 싶을 때 이 차이를 이용합니다.

댓글 0