WHERE 가 행을 거른다면,
HAVING 은 그룹을 거릅니다
3-4에서 "~별"로 묶는 법을 배웠죠. 이번엔 그 묶인 결과에 조건을 거는 법 — HAVING 입니다. 완전히 새로운 문법이 아니라 GROUP BY 의 보조 장치라서, WHERE → GROUP BY → HAVING 순서 하나만 챙기면 끝나는 짧은 강의예요.
이번 섹션의 여정
완료 ✓
완료 ✓
지금 여기
핵심 + 뻥튀기 함정 ⭐
문법 마무리
강의 메인
그룹 결과에도 조건이 필요합니다
3-4에서 GROUP BY 로 “카테고리별 상품 수” 를 뽑았습니다. 그런데 욕심이 하나 더 생기죠 — “카테고리 전부 말고, 상품이 6개 이상인 카테고리만 보고 싶다”. 조건이니까 WHERE 를 떠올리기 쉬운데, 아쉽게도 WHERE 는 행을 거르는 도구지 묶인 그룹을 거르는 도구가 아닙니다.
이럴 때 쓰는 게 HAVING 입니다.
HAVING 은 그룹화된 결과에 거는 거름망 — “WHERE 의 그룹 버전”. 새로운 문법이 아니라 GROUP BY 의 보조 장치입니다.
WHERE vs HAVING — 거름망이 두 번
가장 중요한 차이는 딱 하나, “언제 거르는가” 입니다. SQL 의 거름망은 묶기 전과 묶은 후, 두 번 들어갈 수 있어요.
WHERE 가 행을 줄여놓으면, GROUP BY 가 그 행들을 묶고, HAVING 이 묶인 결과 위에 다시 한 번 거름망을 댑니다.
WHERE 는 GROUP BY 전, HAVING 은 GROUP BY 후. 이 순서만 잡으면 둘은 절대 안 헷갈립니다.
실습 — 상품 6개 이상인 카테고리만
3-4의 “카테고리별 상품 수” 쿼리에 HAVING 한 줄만 붙이면 됩니다. 직접 쳐보세요.
SELECT
category_id,
COUNT(*) AS 상품수
FROM
products
GROUP BY
category_id
HAVING
COUNT(*) >= 6;| category_id | 상품수 |
|---|---|
| 1 | 8 |
| 2 | 7 |
| 3 | 6 |
3-4에서는 5줄이 나오던 쿼리가 — “6개 이상” 조건 하나로 3줄이 됐습니다. 통과한 건 의류(8개)·전자기기(7개)·식품(6개)뿐이에요.
WHERE 로 쓰면 안 되나요? — 에러입니다
“조건이면 그냥 WHERE 쓰면 되지 않나?” — 직접 해보면 바로 답이 나옵니다.
WHERE 에 COUNT 조건
WHERE 는 그룹화 전, 행 단위로 동작합니다. 그 시점엔 COUNT(*) 결과라는 게 아직 세상에 없어요 — 그래서 즉시 에러.
HAVING 에 COUNT 조건
HAVING 은 그룹화 후에 동작합니다. 그룹마다 COUNT(*) 가 이미 계산돼 있는 상태라 — 조건을 걸 수 있습니다.
조건에 집계 함수(COUNT, SUM, AVG, MIN, MAX)가 들어가면 → 무조건 HAVING. 이거 하나면 90%는 해결됩니다.
WHERE 와 HAVING 같이 쓰기
둘은 경쟁 관계가 아니라 함께 쓰는 관계고, 실무에서 자주 그렇게 씁니다. “가격 1만원 이상인 상품들 중에서 — 카테고리별 평균 가격이 3만원 넘는 카테고리만” 을 뽑아볼게요.
SELECT
category_id,
AVG(price) AS 평균가격
FROM
products
WHERE
price >= 10000 -- (1) 행 단위 거르기
GROUP BY
category_id -- (2) 카테고리별 묶기
HAVING
AVG(price) >= 30000; -- (3) 그룹 결과 거르기| category_id | 평균가격 |
|---|---|
| 1 | 55750.0000 |
| 2 | 52333.3333 |
| 5 | 41000.0000 |
(1)→(2)→(3) — 쿼리를 쓰는 순서가 곧 처리되는 순서입니다. 이 흐름만 잡으면 헷갈릴 일이 없어요. 참고로 도서 카테고리는 평균 28,200원으로 아깝게 탈락했습니다.
한눈에 정리
SELECT
컬럼,
집계함수
FROM
테이블
WHERE
행조건 -- 집계 함수 ✕ (GROUP BY 전)
GROUP BY
컬럼
HAVING
그룹조건; -- 집계 함수 ✓ (GROUP BY 후)| WHERE | HAVING | |
|---|---|---|
| 시점 | GROUP BY 전 | GROUP BY 후 |
| 거르는 것 | 원본 행 | 그룹 결과 |
| 집계 함수 | ✕ 사용 불가 | ✓ 사용 가능 |
category_id = 1 같은 집계 없는 조건은 HAVING 에 써도 동작은 하지만,
정석은 WHERE 입니다. 묶기 전에 행을 줄여놓는 쪽이 빠르고, 읽는 사람에게도
의도가 명확해요.
자주 막히는 지점
COUNT(*) 같은 집계 함수가 WHERE 자리에 들어가 있다는 신호입니다. WHERE 가
동작하는 시점엔 집계 결과가 아직 없어요.
SELECT 에서 만든 별칭(AS 상품수)을 WHERE 에 쓰면 에러 — WHERE 시점엔 그
별칭이 아직 만들어지기 전이거든요.
HAVING 상품수 >= 6 처럼 쓰세요.HAVING category_id = 1 처럼 집계 없는 조건도 MySQL 에선 돌아가긴 합니다.
다만 그룹 조건이 아닌 행 조건은 WHERE 자리가 맞아요.
이걸로 거르고(WHERE) → 묶고(GROUP BY) → 또 거르는(HAVING) 흐름이 완성됐습니다. 연습 문제로 손에 붙이고 나면 — 다음은 드디어 두 테이블 합치기, JOIN 입니다. 이 강의에서 가장 중요한 한 강이에요.