효율적인 집계를 위해 "수준"별 필터링(예: 먼저 필터링한 다음 그룹별로 합계를 계산하고 전체 집합에 대해 계산)을 수행할 때, 윈도우 함수(OVER())와 중첩된 GROUP BY를 사용합니다.
예제: 각 매니저별 최대 주문 금액을 찾되, '지급' 상태의 주문만 포함하고, 그 후 모든 주문 중 절대 최대 금액을 가진 매니저의 이름을 출력합니다.
WITH PaidOrders AS ( SELECT ManagerID, SUM(OrderAmount) AS TotalPaid FROM Orders WHERE Status = 'paid' GROUP BY ManagerID ), WithMax AS ( SELECT *, MAX(TotalPaid) OVER() AS MaxTotalPaid FROM PaidOrders ) SELECT ManagerID, TotalPaid FROM WithMax WHERE TotalPaid = MaxTotalPaid;
이와 같은 접근(CTE + 윈도우 함수)은 다단계 필터링과 집계를 구현할 수 있게 해줍니다.
꼬리 질문: "그룹화(GROUP BY) 전에 WHERE 필터를 실행하는 것과 HAVING을 사용하여 후에 필터링하는 것의 차이는 무엇입니까? 이로 인해 보고서에서 자주 발생하는 문제는 무엇입니까?"
답변: WHERE는 그룹화 전에 행을 제거하므로, 엄격한 입력 집합을 제공합니다. HAVING은 집계된 그룹을 필터링하므로, 논리가 일치하지 않으면 "불필요한" 행을 일시적으로 "남겨둘" 수도 있습니다. 잘못된 필터 위치는 최종 집계의 오류 또는 보고서의 잘못된 결과로 이어지는 경우가 많습니다.
-- '지급' 상태에 대해서만 합계를 받기 위해 WHERE 사용 SELECT ManagerID, SUM(OrderAmount) FROM Orders WHERE Status = 'paid' GROUP BY ManagerID; -- 아니면 모든 것에 대해 합계를 계산한 다음 HAVING으로 잘라내기 SELECT ManagerID, SUM(OrderAmount) FROM Orders GROUP BY ManagerID HAVING SUM(OrderAmount) > 1000;
이야기
프로젝트: 판매 보고서, 감사 확인.
오류: 개발자가 WHERE 대신 HAVING Status='paid'를 사용하여 집계에 지불되지 않은 주문이 포함되어 인력의 연간 KPI가 잘못 계산되었습니다.
이야기
프로젝트: 은행 분석.
오류: 복잡한 집계에 PARTITION BY 없이 윈도우 함수를 사용하려 했기 때문에 집계가 전체 테이블을 기준으로 계산되어 부서 예산이 잘못 계산되었습니다 — 수동으로 복구해야 했습니다.
이야기
프로젝트: 전자상거래, 주문 통계.
오류: 최적화 시 서브쿼리에 윈도우 함수를 중첩했음을 고려하지 않아 서버가 데이터를 여러 번 처리하게 되었고, 쿼리는 단순히 이중 GROUP BY보다 20배 느리게 작동하게 되었습니다.