본문으로 건너뛰기

HAVING 절

SQLD 목차SQL 기본레슨 18 / 35

목차

HAVING 절은 GROUP BY로 묶은 그룹 가운데 조건에 맞는 그룹만 남깁니다. WHERE가 행을 거른다면, HAVING은 그룹을 거릅니다.

"평균 월급이 450 이상인 부서는 어디인가?"는 부서마다 평균을 구한 뒤에야 답할 수 있습니다. 평균은 행을 묶은 다음에 생기는 값이라, 행을 하나씩 보는 WHERE에는 이 조건을 쓸 수 없습니다. 묶은 뒤의 그룹을 거르는 일은 HAVING 절이 맡습니다.

7단계 중 1단계. GROUP BY DEPTNO가 EMP 6행을 그룹 4개로 묶습니다.

1그룹을 거르는 HAVING

EMP를 DEPTNO로 묶으면 10번·30번 그룹에 1행씩, 20번 그룹에 3행, NULL 그룹에 정하늘(1005) 1행이 들어갑니다. 그룹마다 평균을 내면, 20번 그룹은 (380 + 410 + 470) ÷ 3 = 420이고, 10번은 520, 30번은 450, NULL 그룹은 300입니다. HAVING AVG(SAL) >= 450⁠이 견주는 값은 그룹에 하나뿐인 평균입니다. 그룹 안의 행을 하나씩 보지 않습니다. 평균이 450보다 작은 20번(420)과 NULL 그룹(300)이 빠집니다. 20번 그룹에는 SAL이 470인 강도윤도 있지만 그룹째 빠집니다. 30번은 평균이 450으로 기준값과 같아서 남습니다. NULL 그룹도 똑같이 조건을 거쳐 빠졌고, 결과는 10번·30번 두 줄입니다.

2WHERE와 HAVING

같은 450으로 HAVING 대신 WHERE SAL >= 450을 쓰면, 묶기 전의 행마다 SAL을 봅니다. 이서연(380)·박지호(410)·정하늘(300)이 빠지고 3행이 남습니다. 남은 3행을 묶으면 20번 그룹에는 강도윤(470) 한 행만 남습니다. 그래서 WHERE 쪽 결과에는 20번이 평균 470으로 들어가 3줄이 됩니다. 거르는 때(묶기 전·후)와 거르는 대상(행·그룹)이 달라서 결과가 다릅니다.

구분WHEREHAVING
거르는 때묶기 전묶은 뒤
거르는 대상행그룹
집계 함수 조건못 씀(ORA-00934)씀
이 예의 결과3줄(20번 470)2줄

처리 순서에서 WHERE는 GROUP BY보다 앞이라 그때는 평균이 아직 없습니다. 그래서 집계 함수 조건은 HAVING에만 씁니다. GROUP BY에 쓴 열의 조건(DEPTNO = 20)은 어느 쪽에 써도 결과가 같고, WHERE에 쓰면 묶기 전에 행이 줄어듭니다.

3HAVING에 쓸 수 있는 것

HAVING에도 SELECT와 같은 제한이 걸립니다. GROUP BY에 쓴 열, 집계 함수, 상수와 이것들로 만든 식만 올 수 있고, 집계 함수는 SELECT에 없어도 됩니다. GROUP BY에 없는 SAL을 쓰면 그룹마다 SAL이 여럿이라 ORA-00979 오류입니다.

GROUP BY DEPTNO
HAVING SAL > 400

HAVING은 SELECT보다 먼저 처리되어, 시험 기준으로는 SELECT의 별칭 대신 집계 함수를 다시 씁니다. Oracle 23부터는 HAVING의 별칭도 받지만, 시험 답은 이 규칙으로 고릅니다.

예제

그림의 쿼리입니다.

SELECT DEPTNO,
  AVG(SAL)
FROM EMP
GROUP BY DEPTNO
HAVING AVG(SAL) >= 450
ORDER BY DEPTNO;
DEPTNOAVG(SAL)
10520
30450

HAVING 줄을 빼고 WHERE로 행을 먼저 거른 쿼리입니다.

SELECT DEPTNO,
  AVG(SAL)
FROM EMP
WHERE SAL >= 450
GROUP BY DEPTNO
ORDER BY DEPTNO;
DEPTNOAVG(SAL)
10520
20470
30450

SELECT에 없는 COUNT(*)로 사원이 2명 이상인 부서만 골라 월급 합계를 봅니다.

SELECT DEPTNO,
  SUM(SAL)
FROM EMP
GROUP BY DEPTNO
HAVING COUNT(*) >= 2
ORDER BY DEPTNO;
DEPTNOSUM(SAL)
201260

GROUP BY가 없으면 테이블 전체가 한 그룹이고, HAVING은 그 한 그룹을 거릅니다. 조건이 참이면 1행, 거짓이면 0행입니다.

SELECT COUNT(*),
  SUM(SAL)
FROM EMP
HAVING SUM(SAL) > 2000;
COUNT(*)SUM(SAL)
62530

HAVING SUM(SAL) > 3000⁠이면 합계 2530이 맞지 않아 0행입니다.

시험 포인트

  • WHERE는 묶기 전에 행을 거르고, HAVING은 묶은 뒤에 그룹을 거릅니다. 처리 순서는 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY입니다.
  • 집계 함수가 들어간 조건은 HAVING에 씁니다. WHERE에 쓰면(WHERE AVG(SAL) > 400) Oracle은 ORA-00934 오류를 냅니다.
  • HAVING에는 GROUP BY 열·집계 함수·상수와 그 식만 오고, 시험 기준으로 SELECT의 별칭은 못 씁니다.
  • GROUP BY 열의 조건은 WHERE·HAVING 어디에 써도 결과가 같습니다.

확인 문제

1. 다음 쿼리의 결과는 몇 줄일까요?

SELECT DEPTNO,
  COUNT(*)
FROM EMP
GROUP BY DEPTNO
HAVING COUNT(*) = 1
ORDER BY DEPTNO;
정답

3줄입니다.

DEPTNOCOUNT(*)
101
301
NULL1

그룹 넷의 행 수는 1·3·1·1이라 20번만 빠집니다. 정하늘 한 행으로 된 NULL 그룹도 행 수가 1이라 남습니다.

2. Oracle에서 오류가 나는 쿼리를 고르세요.

  • ① SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING COUNT(*) > 1;
  • ② SELECT DEPTNO, COUNT(*) FROM EMP WHERE MAX(SAL) >= 450 GROUP BY DEPTNO;
  • ③ SELECT COUNT(*) FROM EMP HAVING COUNT(*) > 1;
  • ④ SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING DEPTNO = 20;
정답

②입니다. MAX(SAL)은 그룹의 행을 다 모아야 정해지는 값인데, WHERE는 묶기 전에 행마다 처리되어 ORA-00934 오류가 납니다. ①은 묶은 뒤 그룹마다 행 수로 거르는 조건이라 되고, 행이 셋인 20번 한 줄이 나옵니다. ③은 GROUP BY 없이 테이블 전체를 한 그룹으로 보고 6을 냅니다. ④는 GROUP BY에 쓴 열의 조건이라 HAVING에 써도 되고, 20번 한 줄이 나옵니다.

3. 다음 쿼리의 결과는 무엇일까요? WHERE와 HAVING이 처리되는 차례를 따라가 보세요.

SELECT DEPTNO,
  COUNT(*)
FROM EMP
WHERE SAL > 400
GROUP BY DEPTNO
HAVING COUNT(*) >= 2
ORDER BY DEPTNO;
정답

20번 한 줄이고, COUNT(*)는 2입니다.

DEPTNOCOUNT(*)
202
  • WHERE가 먼저 SAL이 400 이하인 이서연(380)과 정하늘(300)을 걸러 4행이 남습니다.
  • 남은 4행을 묶으면 10번 1행, 20번 2행(박지호·강도윤), 30번 1행입니다.
  • HAVING이 행이 2개 이상인 20번 그룹만 남깁니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

SQLD 목차로