윈도우 함수와 QUALIFY 절 — 순위 계산 결과를 곧바로 필터링하기
ClickHouse Dictionary 및 QUALIFY 절 공식 문서 종합 (웹 리서치, 2026) — ClickHouse 공식 문서(sql-reference/dictionaries, sql-reference/statements/select/qualify) ClickHouse 공식 문서 QUALIFY clause
이 모듈을 다 읽으면
- 왜 WHERE/HAVING으로 윈도우 함수 결과를 필터링할 수 없는지 실행 순서 관점에서 설명할 수 있다
- QUALIFY + ROW_NUMBER()로 그룹별 최신 행만 남기는 중복제거 패턴을 작성할 수 있다
clickhouse-learn-04에서 다룬 ReplacingMergeTree+FINAL의 중복 제거 방식과 대비되는, 쿼리 시점에 즉석으로 그룹별 순위를 매겨 원하는 행만 골라내는 QUALIFY 절과 윈도우 함수 조합을 정리한다.
왜 WHERE/HAVING으로는 윈도우 함수 결과를 못 거르나
SQL 쿼리 실행 순서상 WHERE는 원본 행을 거르는 가장 이른 단계, HAVING은 GROUP BY 집계 이후 단계에서 동작하는데, 윈도우 함수(OVER 절을 쓰는 ROW_NUMBER/RANK 등)는 이 둘보다 더 뒤에 계산된다. 즉 WHERE나 HAVING 시점에는 아직 윈도우 함수의 결과값 자체가 존재하지 않으므로, 그 결과를 조건으로 걸러내려는 시도는 애초에 성립하지 않는다 — QUALIFY는 이 문제를 풀기 위해 윈도우 함수가 계산되고 난 '이후' 단계에서 동작하도록 설계된 절이다.
핵심 포인트
- 윈도우 함수는 WHERE/HAVING보다 늦게 계산되므로, 그 시점엔 윈도우 함수 결과가 아직 없어 WHERE/HAVING으로 못 거름
- QUALIFY는 윈도우 함수 계산 '이후' 단계에서 동작하도록 설계된 전용 필터 절
전형적 패턴 — ROW_NUMBER()로 그룹별 최신 행만 남기기
가장 흔한 활용은 SELECT ... QUALIFY ROW_NUMBER() OVER (PARTITION BY 키 ORDER BY 정렬기준 DESC) = 1 형태로, 각 키(예: user_id)별로 정렬 기준(예: 이벤트 시각) 내림차순 1등만 남기는 중복제거다. WHERE는 이 윈도우 계산이 일어나기 전에 원본 행을 먼저 좁히는 데(예: 최근 30일 데이터만) 쓰이고, QUALIFY는 그 다음 단계에서 파티션별 순위를 매긴 결과를 걸러내는 역할을 맡는다 — 여러 컬럼 기준의 복잡한 중복제거 로직에서는 GROUP BY로 억지로 표현하는 것보다 이 패턴이 더 명확하고 성능도 낫다.
핵심 포인트
- QUALIFY ROW_NUMBER() OVER (PARTITION BY 키 ORDER BY 기준 DESC) = 1 패턴이 그룹별 최신 행 중복제거의 전형적 관용구
- WHERE는 윈도우 계산 전 원본 행 축소, QUALIFY는 윈도우 계산 후 순위 필터링 — 역할이 서로 다른 단계