AI 시대 DB 모델링 & SQL 완벽 마스터3-5 HAVING — 그룹 조건
테크타니 LEARN — 섹션 03 · SQL 핵심 문법 — 한방 압축

WHERE 가 행을 거른다면,
HAVING 은 그룹을 거릅니다

3-4에서 "~별"로 묶는 법을 배웠죠. 이번엔 그 묶인 결과에 조건을 거는 법 — HAVING 입니다. 완전히 새로운 문법이 아니라 GROUP BY 의 보조 장치라서, WHERE → GROUP BY → HAVING 순서 하나만 챙기면 끝나는 짧은 강의예요.

난이도쉬움소요약 4분준비물3-4 완료 (GROUP BY)실습 DBshop (DBeaver)

이번 섹션의 여정

3-1 ~ 3-3

완료 ✓

3-4 GROUP BY

완료 ✓

3-5 HAVING

지금 여기

3-6 ~ 3-7 JOIN

핵심 + 뻥튀기 함정 ⭐

3-8 CASE / 서브쿼리

문법 마무리

섹션 4 — DB 모델링

강의 메인

그룹 결과에도 조건이 필요합니다

3-4에서 GROUP BY 로 “카테고리별 상품 수” 를 뽑았습니다. 그런데 욕심이 하나 더 생기죠 — “카테고리 전부 말고, 상품이 6개 이상인 카테고리만 보고 싶다”. 조건이니까 WHERE 를 떠올리기 쉬운데, 아쉽게도 WHERE 는 행을 거르는 도구지 묶인 그룹을 거르는 도구가 아닙니다.

이럴 때 쓰는 게 HAVING 입니다.

한 줄 정의

HAVING 은 그룹화된 결과에 거는 거름망 — “WHERE 의 그룹 버전”. 새로운 문법이 아니라 GROUP BY 의 보조 장치입니다.

WHERE vs HAVING — 거름망이 두 번

가장 중요한 차이는 딱 하나, “언제 거르는가” 입니다. SQL 의 거름망은 묶기 전과 묶은 후, 두 번 들어갈 수 있어요.

SQL 처리 순서 — 거름망 2개의 위치
원본 행 전체
↓ ① WHERE 행 단위 거름망 — 묶기 전에 거른다
남은 행
↓ ② GROUP BY 남은 행을 ~별로 묶는다
그룹 결과
↓ ③ HAVING 그룹 단위 거름망 — 묶은 후에 거른다
최종 결과
 
순서는 항상 WHERE → GROUP BY → HAVING

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;
DBeaver — SQL Editor (Ctrl + Enter)
SELECT category_id, COUNT(*) AS 상품수 FROM products GROUP BY category_id HAVING COUNT(*) >= 6;
category_id상품수
18
27
36
카테고리 5개 중 3개만 통과 — 도서(5개) · 뷰티(4개)는 탈락
3 rows fetched · 0.004s

3-4에서는 5줄이 나오던 쿼리가 — “6개 이상” 조건 하나로 3줄이 됐습니다. 통과한 건 의류(8개)·전자기기(7개)·식품(6개)뿐이에요.

WHERE 로 쓰면 안 되나요? — 에러입니다

“조건이면 그냥 WHERE 쓰면 되지 않나?” — 직접 해보면 바로 답이 나옵니다.

✕ 자주 쓰는 오답

WHERE 에 COUNT 조건

WHERE 는 그룹화 전, 행 단위로 동작합니다. 그 시점엔 COUNT(*) 결과라는 게 아직 세상에 없어요 — 그래서 즉시 에러.

✓ 정답

HAVING 에 COUNT 조건

HAVING 은 그룹화 후에 동작합니다. 그룹마다 COUNT(*) 가 이미 계산돼 있는 상태라 — 조건을 걸 수 있습니다.

DBeaver — WHERE 에 집계 함수를 넣으면
SELECT
category_id,
COUNT(*)
FROM
products
WHERE
COUNT(*) >= 6 -- ❌ 여기가 문제
GROUP BY
category_id;
 
SQL Error [1111] [HY000]: Invalid use of group function
빨간 에러 — 실무에서도 정말 자주 마주치는 메시지입니다
📌 쉽게 외우는 법

조건에 집계 함수(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) 그룹 결과 거르기
처리 흐름 — 거름망 두 번
원본 products 30행
↓ (1) WHERE price >= 10000 — 1만원 미만 행 제거
28행 (8,000원 케이블 · 9,000원 초콜릿 탈락)
↓ (2) GROUP BY category_id — 카테고리별 묶기
5그룹
↓ (3) HAVING AVG(price) >= 30000 — 평균 3만원 미만 그룹 제거
3그룹 — 의류 · 전자기기 · 뷰티
DBeaver — 실행 결과
category_id평균가격
155750.0000
252333.3333
541000.0000
3 rows fetched · 0.004s

(1)→(2)→(3) — 쿼리를 쓰는 순서가 곧 처리되는 순서입니다. 이 흐름만 잡으면 헷갈릴 일이 없어요. 참고로 도서 카테고리는 평균 28,200원으로 아깝게 탈락했습니다.

한눈에 정리

SELECT
  컬럼,
  집계함수
FROM
  테이블
WHERE
  행조건            -- 집계 함수 ✕ (GROUP BY 전)
GROUP BY
  컬럼
HAVING
  그룹조건;         -- 집계 함수 ✓ (GROUP BY 후)
WHERE vs HAVING — 최종 비교
WHEREHAVING
시점GROUP BY 전GROUP BY 후
거르는 것원본 행그룹 결과
집계 함수✕ 사용 불가✓ 사용 가능
조건에 COUNT · SUM · AVG 가 보이면 → 무조건 HAVING
일반 컬럼 조건은 어디에?

category_id = 1 같은 집계 없는 조건은 HAVING 에 써도 동작은 하지만, 정석은 WHERE 입니다. 묶기 전에 행을 줄여놓는 쪽이 빠르고, 읽는 사람에게도 의도가 명확해요.

자주 막히는 지점

① Invalid use of group function 에러가 떠요

COUNT(*) 같은 집계 함수가 WHERE 자리에 들어가 있다는 신호입니다. WHERE 가 동작하는 시점엔 집계 결과가 아직 없어요.

FIX ▸집계 함수가 든 조건을 그대로 HAVING 으로 옮기세요 — GROUP BY 아랫줄에.
② 별칭으로 조건을 걸었더니 Unknown column 에러예요

SELECT 에서 만든 별칭(AS 상품수)을 WHERE 에 쓰면 에러 — WHERE 시점엔 그 별칭이 아직 만들어지기 전이거든요.

FIX ▸MySQL 은 HAVING 에서는 별칭을 허용합니다 — HAVING 상품수 >= 6 처럼 쓰세요.
③ 일반 조건을 HAVING 에 넣어도 되던데요?

HAVING category_id = 1 처럼 집계 없는 조건도 MySQL 에선 돌아가긴 합니다. 다만 그룹 조건이 아닌 행 조건은 WHERE 자리가 맞아요.

FIX ▸동작은 하지만 정석은 WHERE — 묶기 전에 줄이는 쪽이 빠르고 의도도 명확합니다.

이걸로 거르고(WHERE) → 묶고(GROUP BY) → 또 거르는(HAVING) 흐름이 완성됐습니다. 연습 문제로 손에 붙이고 나면 — 다음은 드디어 두 테이블 합치기, JOIN 입니다. 이 강의에서 가장 중요한 한 강이에요.

NEXT LESSON3-5 연습 문제

WHERE → GROUP BY → HAVING 순서가 손에 붙도록, shop DB 에 직접 쳐보며 확인합니다.

GO ▸ 연습 문제 풀기