SQL에서 Having 절은 SELECT 문에서 집계 함수로 집계된 자료를 다시한번 필터링 하기 위한 용도로 사용됩니다. 데이터 를 필터링 하기 위한 용도는 WHERE 절과 HAVING절이 사용되는 데 WHERE 절은 집계되지 않은 자료에 대한 조건이고 HAVING 절은 집계된 자료에 대한 조건이라고 생각하면 됩니다.
HAVING 절의 사용법은 아래와 같습니다.
SELECT column, column, column...
FROM table_name
WHERE search_condition GROUP BY column_name(s) HAVING search_condition ORDER BY column_name(s)
그러면 하나씩 예들 들어가면서 알아보도록 하겠습니다.
Product 테이블
SELECT ProductName FROM Products WHERE RetailPrice=MAX(RetailPrice) -- 오류 메시지 --집계가 HAVING 절 이나 SELECT 목록에 포함된 하위 쿼리 내에 없으면 --WHERE 절에 나타날 수 없습니다. 또한 집계 중인 열은 외부 참조입 니다.
위에서 설명했듯이 집계함수를 WHERE 절에서 사용하면 오류가 나면서 쿼리문이 실행되지 않습니다. 그러면 위와 같은 구문은 왜 오류가 나는 걸까요? 단순히 집계함수는 WHERE 절에서 사용할 수 없다는 것으로 알고 있기 보단 실제 원인이 무엇인지를 알아야 정확한 지식이 되고 실제 현업에서 문제 없이 사용할 수 있는 토대가 될 수 있습니다.
그 이유는 집계함수의 용도가 SELECT를 하지 않으면 나올 수 없는 값이기 때문입니다. 집계 함수의 종류들인 SUM, AVG, MAX, MIN 등의 함수를 모두 실제 사용하기 위해서 SELECT 를 통해서만 사용할 수 있기 때문에 WHERE 절에 직 접 집계함수를 이용해서 쿼리문을 만들 수 없게 되는 것입니다.
그러면 WHERE 절에서 SELECT를 사용할 수 있다면 WHERE 절 내에서도 집계함수를 사용할 수 있는 것 아닌가? 이렇게 생각했다면 핵심을 제대로 집으신 겁니다. 그렇습니다. WHERE 절 내에서 서브쿼리를 이용한다면 집계함수를 WHERE 절 안에서 얼마든지 사용할 수 있습니다.
SELECT ProductName FROM Products WHERE RetailPrice =(SELECT MAX(RetailPrice) FROM Products) WHERE 절 안에 위와 같이 서브쿼리를 이용해서 쿼리문을 작성한다면 아무 문제가 없이 정확히 원하는 데이터가 출력되 게 됩니다.
SELECT Customers.CState AS 지역, SUM(Order_Details.QuantityOrdered * Order_Details.QuotedPrice) AS 주 문합계 FROM (Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID) INNER JOIN Order_Details ON Orders.OrderNumber = Order_Details.OrderNumber GROUP BY Customers.CState HAVING SUM(Order_Details.QuantityOrdered * Order_Details.QuotedPrice) > 5000 AND CState IN ('강남구', '마포구', '용산구')
위의 예제는 강남구, 마포구, 용산구에서 주문 합계가 5000 이 넘는 주문의 합계를 출력하는 쿼리문입니다. SELECT에서 SUM 함수를 통해서 집계한 자료를 바탕으로 HAVING 절을 이용해서 필터링을 해서 원하는 자료를 출력할 수 있습니다.
SELECT Customers.CState AS 지역, SUM(Order_Details.QuantityOrdered * Order_Details.QuotedPrice) AS 주 문합계 FROM (Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID) INNER JOIN Order_Details ON Orders.OrderNumber = Order_Details.OrderNumber WHERE Customers.CState IN ('강남구', '마포구', '용산구') GROUP BY Customers.CState HAVING SUM(Order_Details.QuantityOrdered * Order_Details.QuotedPrice) > 5000
위의 예제를 똑같은 쿼리문을 WHERE 절을 이용해서 만들어 낸 자료입니다.
WHERE 절을 이용해서 먼저 한번 필터링을 거칠 수 있다면 이 방법을 사용하는 것이 더 효율적입니다.
위의 예에서 알 수 있듯이 HAVING 절은 SELECT에서 한번 집계한 자료를 가지고 다시 한번 필터링을 하는 데 사용한다고 생각하면 됩니다.
예를 들어 다음과 같은 경우가 있을 수 있습니다.
예) 모든 제품들의 평균 매출액보다 큰 총 매출액을 표시하시오 (AVG와 HAVING을 사용할 수 있음) 예) 양파와 호박을 모두 포함하는 조리법을 출력하시오 (Count와 HAVING을 사용할 수 있음)
예) 지역에서 후원금의 총액이 1억원 이상인 후보의 리스트를 출력하시오 (SUM과 HAVING을 사용할 수 있음)
SELECT Customers.FirstName + ' ' + Customers.LastName AS 성명, Orders.OrderDate,SUM(Order_Details.QuotedPrice * Order_Details.QuantityOrdered) AS 주문금액 FROM (Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID) INNER JOIN Order_Details
ON Orders.OrderNumber = Order_Details.OrderNumber GROUP BY Customers.FirstName, Customers.LastName, Orders.OrderDate HAVING SUM(Order_Details.QuotedPrice * Order_Details.QuantityOrdered) > 10000
위의 예제는 고객명과 주문날짜를 출력하면서 각 고객들이 주문한 금액이 10,000원이 넘는 리스트를 출력하는 예제입니 다.
고객과 주문날짜를 같이 출력하도록 했기때문에 한 고객의 경우라도 날짜별 주문 금액을 계산해서 10,000원이 넘는 리스 트를 출력하게 됩니다. 만약 날짜를 제거한다면 고객별 주문 금액이 출력되게 되므로 각 고객은 한번만 출력될 것입니다..
'MSSQL' 카테고리의 다른 글
데이터 그룹화(GROUP BY) (1) | 2024.11.18 |
---|---|
집계함수 (0) | 2024.11.17 |
서브쿼리(Sub Query) (3) | 2024.11.16 |
데이터베이스 조인(UNION) (2) | 2024.11.15 |
외부조인 (0) | 2024.11.14 |