SELECT 문의 실행 순서
SQL을 읽을 때 눈으로 보는 순서와 실제 실행 순서가 다릅니다. 이것을 알면 WHERE / GROUP BY / HAVING에 무엇을 써야 하는지 헷갈리지 않습니다.
SELECTFROMWHERE실행 순서 SELECT 논리 실행 순서
- 1
FROM— 테이블 결합 - 2
WHERE— 개별 행 필터 - 3
GROUP BY— 행을 그룹으로 - 4
HAVING— 그룹 필터 - 5
SELECT— 컬럼 선택 + 별칭 - 6
ORDER BY— 결과 정렬
작성 순서는 SELECT → FROM → WHERE … 이지만 평가는 FROM부터 시작합니다.
작성 순서 vs 실행 순서
SQL은 영어 문장처럼 자연스럽게 SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY 순서로 작성합니다. 그런데 DB가 실제로 처리하는 순서는 다릅니다.
작성 순서 실행 순서
-------- --------
SELECT ... 1. FROM ← 어디서 가져올지
FROM ... 2. WHERE ← 개별 행 필터
WHERE ... 3. GROUP BY ← 그룹화
GROUP BY ... 4. HAVING ← 그룹 필터
HAVING ... 5. SELECT ← 컬럼 선택
ORDER BY ... 6. ORDER BY ← 정렬
이것을 기억하면 다음 질문들이 전부 풀립니다.
자주 혼동되는 포인트
Q1. WHERE에 AVG(sal) > 2000을 쓸 수 있나요?
사용할 수 없습니다. AVG는 그룹 함수이고, WHERE는 개별 행 필터입니다. 그룹이 아직 만들어지기 전(2단계)이라 AVG 값이 존재하지 않습니다.
그룹 함수 조건은 HAVING(4단계)에 사용합니다.
Q2. SELECT에서 만든 별칭(alias)을 WHERE에서 쓸 수 있나요?
대부분의 DBMS에서 사용할 수 없습니다. SELECT는 5단계인데 WHERE는 2단계라 아직 별칭이 없습니다. 같은 이유로 GROUP BY에서도 보통 사용할 수 없습니다. ORDER BY(6단계)에서는 사용할 수 있습니다. 이미 SELECT가 끝났기 때문입니다.
Q3. NULL은 WHERE에서 어떻게 처리되나요?
NULL과의 비교(= NULL, > NULL)는 항상 UNKNOWN입니다. TRUE가 아니므로 WHERE를 통과하지 못합니다.
NULL 검사는 IS NULL, IS NOT NULL을 사용합니다.
예시: 부서별 평균 급여 Top 3
SELECT d.dname, AVG(e.sal) AS avg_sal
FROM emp e
JOIN dept d ON e.deptno = d.deptno -- 1. FROM/JOIN
WHERE e.job <> 'PRESIDENT' -- 2. 개별 사원 필터
GROUP BY d.dname -- 3. 부서별 그룹
HAVING AVG(e.sal) >= 1500 -- 4. 평균 1500 이상 부서만
ORDER BY avg_sal DESC -- 6. 정렬
LIMIT 3; -- (7) 상위 3개
실습 팁: 이 쿼리를 실습실(
/playground)에서emp-dept스키마로 실행해 봅니다. HAVING 조건을 바꾸거나 WHERE와 HAVING을 서로 옮겨 보면서 결과가 어떻게 달라지는지 관찰하면 실행 순서가 몸에 붙습니다.
한 문장 요약
WHERE는 행을 거르고, HAVING은 그룹을 거릅니다.
이것만 기억해도 SQLD 시험에서 GROUP BY 관련 오답을 크게 줄일 수 있습니다.