아직 얘기 안 한 게 있는데, 집계 함수 쓴 다음에 그룹을 어떻게 필터링하지? 가끔 모든 학부가 필요한 게 아니라 학생이 100명 넘는 학부만 보고 싶을 때가 있잖아. 아니면 평균 연봉이 50,000 넘는 부서만 보고 싶을 수도 있고. 오늘은 HAVING을 써서 집계된 데이터 필터링하는 법을 배워볼 거야.
HAVING이 왜 필요해? 우리에겐 WHERE가 있잖아? 그냥 GROUP BY 뒤에 WHERE 쓰면 되는 거 아냐? :)
그렇게 간단하지 않아! 일단, SQL에서 연산자 순서가 정해져 있고 WHERE는 GROUP BY보다 먼저 실행돼.
그럼 WHERE를 GROUP BY 뒤로 옮기면 되지 않을까?
그것도 안 돼! 보통은 그룹핑 전에 테이블에서 행을 먼저 필터링하고, 그 다음에 그룹핑을 하고, 마지막에 그룹핑된 결과에서 또 필요 없는 걸 걸러내야 할 때가 많아.
그럼 WHERE 연산자를 복사해서 이름만 HAVING으로 바꾸고 GROUP BY 뒤에 놓으면 되지 않을까?
맞아, 바로 그거야! :)
HAVING과 WHERE의 차이점
WHERE는 그룹핑 전에 행을 필터링해.
딸기맛이랑 초콜릿맛 케이크만 남기고 나머지는 빼는 거라고 생각해봐. 이건 WHERE가 하는 일이야.
HAVING은 데이터가 그룹핑되고 집계 함수가 마법을 부린 다음에 필터링해.
예를 들어, 이미 케이크를 테이블별로 그룹핑해서 개수를 세고, 이제 케이크가 3개 넘는 테이블만 남기고 싶을 때 쓰는 거지.
즉, HAVING은 그룹 단위로 데이터를 필터링할 때 써.
HAVING 문법
문법은 거의 WHERE랑 비슷한데, 동작 방식이 조금 달라:
SELECT 컬럼들, 집계_함수들
FROM 테이블
GROUP BY 컬럼들
HAVING 조건;
실행 단계:
- 먼저
WHERE로 행을 필터링해. - 그 다음
GROUP BY로 데이터 그룹핑. - 그룹핑된 결과에 집계 함수 적용.
- 마지막으로
HAVING으로 결과를 필터링.
HAVING 사용 예시
예시 1: 학생 수가 많은 학부 필터링
대학교에서 학생이 100명 넘는 학부가 뭔지 알고 싶다고 해보자. students 테이블이 있다고 가정할게:
| id | name | faculty |
|---|---|---|
| 1 | Alice | Engineering |
| 2 | Bob | Engineering |
| 3 | Charlie | Arts |
| 4 | Daisy | Business |
| 5 | ... | ... |
쿼리:
SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;
여기서 일어나는 일:
- 먼저
GROUP BY로 학생들을faculty별로 그룹핑해. - 그 다음 집계 함수
COUNT(*)가 각 학부의 학생 수를 세. - 마지막으로
HAVING이 학생이 100명 이하인 학부는 다 빼버려.
결과:
| faculty | student_count |
|---|---|
| Engineering | 150 |
| Arts | 120 |
예시 2: 평균 연봉이 높은 부서
평균 연봉이 50,000 넘는 부서만 찾고 싶다고 해보자. employees 테이블이 있다고 가정할게:
| id | name | department | salary |
|---|---|---|---|
| 1 | Alice | IT | 60000 |
| 2 | Bob | HR | 45000 |
| 3 | Charlie | IT | 70000 |
| 4 | Daisy | HR | 52000 |
| 5 | ... | ... | ... |
쿼리:
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
결과:
| department | avg_salary |
|---|---|
| IT | 65000 |
참고: HAVING은 GROUP BY 이후에 계산된 결과에만 작동해.
WHERE, GROUP BY, HAVING 실행 순서
WHERE와 HAVING의 필터링은 서로 다른 단계에서 일어나. 차이를 더 잘 이해하려면 쿼리의 단계별 과정을 보자:
WHERE: 행 필터링.이 단계에서 테이블의 모든 행이 처리돼.
WHERE조건을 통과 못 하면 그 행은 아예 다음 단계로 안 넘어가.GROUP BY: 행 그룹핑.필터링된 행들이
GROUP BY에 지정된 컬럼 기준으로 그룹핑돼.집계 함수:
그룹핑된 데이터에
COUNT(),AVG(),SUM()같은 집계 함수가 적용돼.HAVING: 그룹 필터링.이 단계에서는 집계 결과만 다뤄.
HAVING조건은 그룹에만 적용돼.
HAVING의 특징
특징 1: 집계 함수와 함께 사용
HAVING과 WHERE의 가장 큰 차이는 집계 함수랑 같이 쓸 수 있다는 거야. 예를 들어:
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
이 쿼리에서 AVG(salary)는 WHERE 안에서 쓸 수 없어. 왜냐면 WHERE는 그룹핑 전에 행을 처리하거든. 이런 식으로 쓰면:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
에러가 나: aggregate functions are not allowed in WHERE.
특징 2: 그룹핑 없이도 필터링 가능
GROUP BY 없이도 HAVING을 쓸 수 있어. 이 경우엔 전체가 하나의 그룹으로 간주돼:
SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;
실전 예제
예를 들어, 가게가 있고 sales라는 판매 테이블이 있다고 해보자:
| id | product_id | sales_amount |
|---|---|---|
| 1 | 101 | 200.00 |
| 2 | 102 | 300.00 |
| 3 | 101 | 400.00 |
| 4 | 103 | 150.00 |
쿼리: 총 판매액이 500 넘는 상품 찾기.
SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;
결과:
| product_id | total_sales |
|---|---|
| 101 | 600.00 |
흔한 실수들
WHERE에서 집계 함수 쓰기:
예를 들어:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
에러: WHERE에서는 집계 함수 못 써.
NULL 관련 실수:
데이터에 NULL이 있으면 필터링 결과가 예상과 다를 수 있어. 예를 들어:
SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;
salary 컬럼이 전부 NULL이면 결과가 0이거나 아예 비어 있을 수 있어.
축하해! 이제 집계된 데이터도 자신 있게 필터링할 수 있어! HAVING은 그룹 단위 분석의 핵심이니까, WHERE만으로 부족할 때 꼭 써봐.
GO TO FULL VERSION