**GROUP BY**는 값을 공유하는 행을 그룹화하여 집계 함수가 그룹별로 계산되게 합니다. **HAVING**은 그 그룹들을 필터링합니다(WHERE와 비슷하지만 그룹/집계 대상). 둘은 함께 범주별로 데이터를 요약하고 분석하는 핵심입니다.
GROUP BY — 그룹별 집계
country, () user_count, (age) avg_age
users
country;
**GROUP BY**는 값을 공유하는 행을 그룹화하여 집계 함수가 그룹별로 계산되게 합니다. **HAVING**은 그 그룹들을 필터링합니다(WHERE와 비슷하지만 그룹/집계 대상). 둘은 함께 범주별로 데이터를 요약하고 분석하는 핵심입니다.
country, () user_count, (age) avg_age
users
country;
GROUP BY country는 각 country의 모든 행을 하나의 그룹으로 묶고, 집계 함수(COUNT, AVG)가 각 그룹에 대해 값을 계산합니다. 여러 컬럼으로 그룹화할 수 있습니다:
GROUP BY country, city -- 유일한 (country, city) 조합마다 그룹
-- user가 100명보다 많은 country만 표시
SELECT country, COUNT(*) AS user_count
FROM users
GROUP BY country
HAVING COUNT(*) > 100; -- 집계값으로 필터링
HAVING은 그룹화 후에 집계값에 대해 필터링합니다 — WHERE가 할 수 없는 일입니다(WHERE는 그룹화 전에 개별 행을 필터링).
SELECT country, COUNT(*) AS cnt
FROM users
WHERE active = true -- WHERE: 먼저 행 필터링 (그룹화 전)
GROUP BY country
HAVING COUNT(*) > 100; -- HAVING: 이후 그룹 필터링 (집계값 대상)
WHERE → 개별 행 필터링, 그룹화 전에 실행, 집계 사용 불가
HAVING → 그룹 필터링, 그룹화 후에 실행, 집계와 함께 사용
→ 행 필터링에는 WHERE, 집계된 그룹 필터링에는 HAVING. (가능하면 WHERE로 먼저 필터링
하는 것이 더 효율적 — 그룹화 전에 행을 줄임.)
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
(WHERE는 그룹화 전, HAVING은 후 — 그래서 역할이 다름)
GROUP BY와 HAVING은 분석적 SQL의 핵심입니다. 범주별로 데이터를 요약하고 분석하는 것은 근본적이고 끊임없는 요구이므로(지역별 개수, 제품별 매출, 그룹별 평균), 이해하는 것은 필수적입니다. GROUP BY(행을 그룹화해 집계가 그룹별로 계산되게 함)는 이런 요약 쿼리의 기초이며, 행을 그룹으로 묶어 집계하는 방식을 이해하는 것은 모든 리포팅이나 분석에 필요합니다.
WHERE vs HAVING 구분은 특히 중요하고 자주 혼동됩니다: WHERE는 그룹화 전에 개별 행을 필터링하고(집계 사용 불가), HAVING은 그룹화 후에 그룹을 필터링합니다(집계값 대상). 잘못 쓰면 오류나 틀린 결과가 나오며, 각각이 언제 적용되는지(행 단위 필터링에는 WHERE, 그룹의 집계 단위 필터링에는 HAVING) 이해하는 것이 핵심 역량입니다.
가능하면 WHERE로 먼저 필터링하는 것(더 효율적 — 그룹화 전에 행을 줄임)을 아는 것은 유용한 최적화입니다.
실행 순서와의 연결(WHERE는 그룹화 전, HAVING은 후)은 왜 역할이 다른지를 설명합니다.
그룹화와 집계 필터링은 리포팅과 데이터 분석에서 보편적이고, WHERE 대 HAVING 구분은 정확성에 중요하면서 자주 오해되므로, GROUP BY와 HAVING을 숙달하는 것 — 범주별 집계를 위한 그룹화와 2단계 필터링 모델 — 은 분석적 SQL에 필수적인 핵심적이고 자주 적용되는 지식이자 흔한 인터뷰 주제입니다.