GROUP BY 열에 대한 조건은 WHERE 와 HAVING 중 어디에 둬도 결과가 같다.
SELECT DEPTNO, COUNT(*) FROM EMP WHERE DEPTNO <> 20 GROUP BY DEPTNO ORDER BY DEPTNO;
SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING DEPTNO <> 20 ORDER BY DEPTNO;
DEPTNO COUNT(*)---------- ---------- 10 3 30 6
두 쿼리의 결과는 같다. 다만 WHERE 는 20번 행 5개를 그룹 만들기 전에 버리고, HAVING 은 그룹을 다 만든 뒤 버린다.
처리할 행을 일찍 줄이는 WHERE 쪽이 일반적으로 효율이 좋다.
GROUP BY 에 없는 일반 열은 HAVING 에 쓸 수 없다. HAVING 은 그룹을 보는 절이라 그룹 안의 개별 행 값을 고를 수 없다.
SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING ENAME = 'KING';
SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING ENAME = 'KING' *ERROR at line 1:ORA-00979: "ENAME": must appear in the GROUP BY clause or be used in an aggregate function
SQL 은 적힌 순서(SELECT 가 맨 앞)대로 처리되지 않는다. Oracle 이 내부적으로 실행 계획을 바꾸더라도, 결과는 아래 순서로 처리한 것과 같아야 한다.
⑤ SELECT DEPTNO, COUNT(*) AS CNT ← 보여 줄 열을 고르고 별칭을 붙인다 ① FROM EMP ← 대상 테이블 ② WHERE SAL >= 1500 ← 행을 거른다 ③ GROUP BY DEPTNO ← 그룹을 만든다 ④ HAVING COUNT(*) >= 3 ← 그룹을 거른다 ⑥ ORDER BY CNT DESC ← 정렬한다
순서
절
이 단계에서 보이는 것
1
FROM
테이블의 모든 열
2
WHERE
테이블의 모든 열 (집계 결과는 아직 없음)
3
GROUP BY
그룹
4
HAVING
GROUP BY 열, 집계 결과
5
SELECT
계산식, 별칭이 여기서 생긴다
6
ORDER BY
SELECT 의 별칭·위치 번호까지
이 표 하나로 오늘 본 오류 대부분이 설명된다.
WHERE(2)는 GROUP BY(3)보다 먼저라 집계 함수를 쓸 수 없다 → ORA-00934.
FORD 와 SCOTT 은 연봉이 같아 두 번째 키 ENAME 으로 순서를 정했다. 두 번째 키가 없으면 둘의 순서는 보장되지 않는다.
⚠️ 실습 환경 주의: 교재는 실행 순서를 근거로 GROUP BY·HAVING 에서도 SELECT 별칭을 못 쓴다고 설명한다. 이 노트의 실습 컨테이너(Oracle Database 23ai 계열)는 GROUP BY 별칭과 HAVING 별칭을 허용하는 새 기능이 있어 오류 없이 실행된다. 시험은 별칭을 WHERE·GROUP BY·HAVING 에서 쓸 수 없다는 전통 규칙으로 판단하는 편이 안전하다.
실습 컨테이너에서 실제로 돌려 본 결과다.
SELECT DEPTNO, COUNT(*) AS CNT FROM EMP GROUP BY DEPTNO HAVING CNT > 3 ORDER BY DEPTNO;
DEPTNO CNT---------- ---------- 20 5 30 6
같은 23ai 에서도 WHERE 의 별칭은 여전히 ORA-00904 다. WHERE 가 SELECT 보다 먼저라는 원리는 그대로다.
GROUP BY 위치 번호(GROUP BY 1)는 기본 설정에서 허용되지 않는다. 컨테이너에서는 ORA-03162 가 났다.
HAVING : GROUP BY 로 만든 그룹을 조건으로 거르는 절. 집계 함수를 조건에 쓸 수 있다.
ORA-00934 : 집계 함수를 쓸 수 없는 자리(WHERE 등)에 썼을 때의 오류.
ORA-00904 : 존재하지 않는 열 이름을 썼을 때의 오류. WHERE 에 SELECT 별칭을 쓰면 이 오류가 난다.
논리적 실행 순서 : 결과를 정하는 절 처리 순서. FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
별칭(alias) : SELECT 에서 열이나 식에 붙인 새 이름. SELECT 단계에서 생기므로 ORDER BY 에서만 확실히 쓸 수 있다.
행 조건과 그룹 조건 : 개별 행의 값을 보는 조건은 WHERE, 그룹의 집계 값을 보는 조건은 HAVING 에 둔다.
📝 연습 문제
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
다음 SQL 을 Oracle 에서 실행한 결과로 알맞은 것은?
```sql
SELECT DEPTNO, AVG(SAL) FROM EMP WHERE AVG(SAL) > 2000 GROUP BY DEPTNO;
```
문제 2
다음 중 SELECT 문의 논리적 실행 순서로 알맞은 것은?
문제 3
다음 SQL 의 결과 행 수는? (SAL 이 1500 이상인 사원은 10번 2명, 20번 3명, 30번 3명이다)
```sql
SELECT DEPTNO, COUNT(*) FROM EMP WHERE SAL >= 1500 GROUP BY DEPTNO HAVING COUNT(*) >= 3;
```
문제 4
다음 SQL 을 Oracle 에서 실행한 결과로 알맞은 것은?
```sql
SELECT ENAME, SAL * 12 AS ANNUAL FROM EMP WHERE ANNUAL > 30000;
```
문제 5
EMP 는 14행이다. 다음 SQL 의 결과로 알맞은 것은?
```sql
SELECT COUNT(*) FROM EMP HAVING COUNT(*) > 20;
```