수업에서 GROUP BY를 한 번 배웠었는데 HAVING을 학습하면서 다시 한 번 GROUP BY를 접하고
처음보다 더 흥미롭고 재밌게 느껴져서 이를 주제로 TIL을 작성해보면 좋을 거 같다고 생각이 들었다.
GROUP BY란?
- GROUP BY는 한 컬럼에서 같은 값을 가진 행들을 하나의 그룹으로 묶는 역할을 한다.
- 데이터를 카테고리별로 나눈 뒤, 그 안에서 계산하기 위한 구문
GROUP BY는 언제 필요한가?
아래와 같이 직원들의 부서와 급여를 담은 표를 만들어봤다.
| ENAME(직원명) | DEPTNO(부서 번호) | SAL(급여) |
| TAEU | 10 | 1000 |
| JIO | 10 | 2000 |
| TAEKWAN | 20 | 1500 |
| GYEOL | 20 | 2500 |
| JUNPYO | 30 | 3000 |
여기에서 전제 평균 급여를 구하는 방법은 쉽다.
SELECT AVG(SAL)
FROM EMP;
이 쿼리는 전체 사원의 평균 급여를 하나의 값으로 반환한다.
하지만 부서별 평균 급여를 구하기 위해 단순히 앞선 예제와 비슷하게 쿼리를 작성하면 문제가 발생한다.
SELECT DEPTNO, AVG(SAL)
FROM EMP;
DEPTNO는 여러 개의 값을 가지는데 AVG(SAL)은 하나의 값으로 계산되기 때문에
SQL은 어떤 기준으로 값을 묶어야 할지 알 수 없다.
이때 GROUP BY가 필요하다.
SELECT DEPTNO, AVG(SAL)
FROM EMP
GROUP BY DEPTNO;
이 쿼리에서는 DEPTNO를 기준으로 행을 먼저 묶고
그 그룹 내에서 평균을 계산하게 된다.
이는 SQL의 실행 순서를 알고나면 더 이해하기 쉬워진다.
SQL 실행 순서
SQL은 작성 순서와 실제 실행 순서가 다르다.
- FROM
- WHERE
- GROUP BY
- SELECT
- ORDER BY
GROUP BY가 먼저 실행된 뒤 SELECT가 실행되기 때문에
SELECT에서 사용하는 집계 함수는 이미 그룹이 만들어진 상태를 기준으로 계산된다.
위 예제의 실행 순서를 다시 보면
- FROM에서 테이블을 가져오고
- GROUP BY에서 같은 DEPTNO끼리 묶은 뒤
- 그 다음에 SELECT에서 AVG(SAL)을 계산하는 것이다.
그래서
SELECT DEPTNO, AVG(SAL)
FROM EMP;
와 같이 작성하면,
SQL은 DEPTNO를 기준으로 묶으라는 지시를 받지 못 했기 때문에
어떤 기준으로 평균을 계산해야 하는지 알 수 없다.
이때 GROUP BY를 쓰면 아래와 같이 실행 흐름이 명확해진다.
DEPTNO가 같은 행끼리 묶고, 각 그룹 안에서 평균을 계산하게 된다.
이제 이 GROUP BY와 WHERE, HAVING의 연관성을 살펴볼 것이다.
WHERE
- WHERE은 그룹을 만들기 전에 조건을 거는 구문이다.
- 데이터를 먼저 필터링 한 후, 남은 데이터로 그룹을 만든다.
SELECT DEPTNO, AVG(SAL)
FROM EMP
WHERE SAL >= 2000
GROUP BY DEPTNO;
이 쿼리는
SAL이 2000 이상인 행만 남긴 뒤 그 데이터로 부서별 평균을 계산한다.
하지만 여기서 오류가 발생한다.
WHERE에선 집계 함수를 사용할 수 없는데
이는 집계 함수가 GROUP BY 이후에 계산되기 때문에 실행 순서상 아직 계산되지 않은 집계 결과를 필터링하는 것이 되기 때문이다.
그래서 HAVING을 알아야 한다.
HAVING
- 그룹을 만든 후 조건을 거는 구문
HAVING을 사용하면 GROUP BY로 묶고, 집계 함수를 계산한 뒤 그 결과에 조건을 적용한다.
SELECT DEPTNO, AVG(SAL)
FROM EMP
GROUP BY DEPTNO
HAVING AVG(SAL) > 2000;
이 쿼리는 부서별 평균 급여를 구한 뒤
평균 급여가 2000을 초과하는 부서만 출력하게 된다.
WHERE는 행을 필터링하고, HAVING은 그룹을 필터링한다는 것을 알 수 있다.
느낀점
한 컬럼 내에서 같은 값끼리 그룹화 해주는 GROUP BY와 SELECT문에서 행에 조건을 걸어주는 WHERE, 그리고 SQL의 실행순서로 인한 제약을 극복하기 위해 WHERE과 다른 실행 순서를 가진 HAVING을 학습하면서 데이터에 접근하는 것이 어떤 과정을 갖게 되는지도 파악을 할 수 있었고, 이를 통해 데이터가 어떻게 구조를 이루고 있는지도 다시 한 번 들여다 볼 수 있어서 좋은 학습이었던 것 같다.
'AIBE5 TIL' 카테고리의 다른 글
| [TIL 26/02/12](Java) Stream (0) | 2026.02.12 |
|---|---|
| [TIL 26/02/11](Java) hashCode(), equals() 오버라이딩 (0) | 2026.02.11 |
| [TIL 26/02/10](Java) 인터페이스 (0) | 2026.02.10 |
| [TIL 26/02/09](Java) 상속 (0) | 2026.02.09 |
| [TIL 26/02/06](Java) 접근제어자와 캡슐화 (0) | 2026.02.06 |