개별 주문 데이터를 지역 단위로 집계하고, 합계가 기준 이상인 지역만 조회하는 예제다. 결과 행의 기준, 집계 전후 필터의 차이, 정렬 조건을 구분해 정리한다.
문제와 데이터는 학습용으로 구성했으며, SQL과 결과는 SQLite 기준이다. 특정 코딩테스트 사이트의 문제나 채점 기록은 아니다.
CREATE TABLE orders (region TEXT, amount INTEGER);
INSERT INTO orders VALUES
('서울', 12000),
('부산', 8000),
('서울', 9000),
('부산', 7000),
('대전', 5000);
예제의 금액은 NULL이 없는 0 이상의 정수다. 조회 조건은 다음과 같다.
원본의 한 행은 주문 한 건이지만 결과의 한 행은 지역 하나를 의미한다. 따라서 그룹 기준은 region, 집계 대상은 amount다.
SELECT region, SUM(amount) AS total_amount
FROM orders
GROUP BY region
HAVING SUM(amount) >= 15000
ORDER BY total_amount DESC, region ASC;
| region | total_amount |
|---|---|
| 서울 | 21000 |
| 부산 | 15000 |
서울은 12,000원과 9,000원을 합산한 21,000원이다. 부산은 기준과 정확히 같은 15,000원이므로 포함된다. 대전은 5,000원으로 기준에 미달해 제외된다.
WHERE는 그룹을 만들기 전의 개별 행을 필터링한다. HAVING은 그룹에 대한 조건을 적용한다.
WHERE amount >= 15000
이 조건은 주문 한 건의 금액이 15,000원 이상인 행을 선택한다. 예제에는 해당 주문이 없으므로 남는 행이 없다.
HAVING SUM(amount) >= 15000
이 조건은 지역별 주문 합계를 검사한다. 개별 주문이 기준보다 작아도 같은 지역의 합계가 기준 이상이면 결과에 포함된다. 두 조건은 문법상의 위치뿐 아니라 판정 대상이 다르다.
이 예제는 행 필터링, 그룹 생성, 그룹 조건 검사, 정렬이라는 논리적 흐름으로 이해할 수 있다. 다만 이는 쿼리의 의미를 설명하는 순서이며, 데이터베이스 내부의 물리적 실행 순서를 그대로 나타내는 것은 아니다.
또한 GROUP BY는 결과의 정렬 순서를 보장하지 않는다. 출력 순서가 요구된다면 ORDER BY를 명시해야 한다. 합계가 같은 경우를 고려한 두 번째 정렬 기준도 요구사항에 포함해 작성한다.
집계 쿼리는 먼저 결과 한 행이 무엇을 의미하는지 정해야 한다. 그다음 그룹 기준과 집계식을 선택하고, 조건이 개별 행에 대한 것인지 그룹에 대한 것인지 구분한다. 이번 예제에서는 ‘지역별 합계’가 판단 대상이므로 GROUP BY region과 HAVING SUM(amount)를 사용한다.