본문 바로가기
Data

[Mysql] SQL 문법연습 / HAVING절

by Dora the explorer 2024. 9. 16.
반응형

🥑 학습내용

사용된 문법&함수 COUNT
COALSESCE
JOIN
GROUP BY
HAVING

 

 

 

Lv.4 단골 고객님 찾기

1. 고객별로 주문 건수와 총 주문 금액을 조회하는 SQL 쿼리를 작성해주세요.
    a. 출력 결과에는 고객 이름, 주문 건수, 총 주문 금액이 포함되어야 합니다. 단, 주문을 한 적이 없는 고객도 결과에 포함되어야 합니다.
    b. 기대결과

2. 나라별로 총 주문 금액이 가장 높은 고객의 이름과 그 고객의 총 주문 금액을 조회하는 SQL 쿼리를 작성해주세요.

    a. 기대결과

 

 

1.

내가 제출한 답

SELECT c.customername, 
	count(1) ordercount, 
	sum(totalamount) totalspent
from Customers c left join Orders o on c.CustomerID =o.CustomerID 
group by c.CustomerName

 

정답

SELECT 
    c.CustomerName,
    COUNT(o.OrderID) AS OrderCount,
    COALESCE(SUM(o.TotalAmount), 0) AS TotalSpent
FROM 
    Customers c
LEFT JOIN 
    Orders o ON c.CustomerID = o.CustomerID
GROUP BY 
    c.CustomerName;

 

💡 해석&회고

LEFT JOIN을 사용해 모든 고객을 포함시키고, 주문이 없는 고객도 결과에 포함시킨다.

COUNT(o.OrderID)는 고객별로 주문 건수를 계산하고, COALESCE(SUM(o.TotalAmount), 0)는 주문이 없는 경우 총 주문 금액을 0으로 처리한다. ⬅︎ 나는 이 부분이 틀렸는데 내가 제출한 답도 값은 같게 나오지만 조건에 맞는 정확한 쿼리를 만드려면 COALESCE를 사용해서 주문이 없는 경우를 대체처리해주어야 한다.

*COALESCE (컬럼, 대체값)

GROUP BY c.CustomerName으로 고객별로 결과를 그룹화한다.

 

 

 

??? 2.

내가 제출한 답

* 전혀 감이 오지 않아서 답을 보고 DBeaver 에서 실행해보았다.

여기까지 만들어 내는 것은 쉬운데 나라별로 총추문금액이 가장 높은 고객의 이름만 뽑아내는 것이 어려웠다.

 

 

정답

SELECT 
    c.Country,
    c.CustomerName AS Top_Customer,
    SUM(o.TotalAmount) AS Top_Spent
FROM Customers c JOIN Orders o ON c.CustomerID = o.CustomerID
GROUP BY 
    c.Country, c.CustomerName
HAVING 
    SUM(o.TotalAmount) = (
        SELECT 
            MAX(SumSpent)
        FROM 
            (SELECT 
                 SUM(o2.TotalAmount) AS SumSpent
             FROM 
                 Customers c2
             JOIN 
                 Orders o2 ON c2.CustomerID = o2.CustomerID
             WHERE 
                 c2.Country = c.Country
             GROUP BY 
                 c2.CustomerID) AS Subquery
    );

 

💡 해석&회고

JOIN을 사용해 고객과 주문 데이터를 결합하고, GROUP BY로 나라와 고객 이름별로 그룹화한다.

HAVING 절에서 서브쿼리를 사용해 각 나라별로 가장 높은 총 주문 금액을 가진 고객을 필터링한다.

??? 대부분 이해가 가는데 WHERE c2.country=c.Country 절은 왜 이렇게 지정해주어야 하는지 이해가 잘 가지 않는다ㅠㅠ 

 

이전까지 조건을 주는 문법으로 WHERE만 사용했는데 HAVING을 사용해서 풀어야 하는 경우라 접근하기 어려웠다.

HAVING

해석상 WHERE절과 동일하나 몇 가지 차이점이 있다.

WHERE 모든 레코드(행)에 조건 적용 일반조건
HAVING GROUP BY절을 통해 만들어진 그룹들에만 조건 적용 집계함수 포함한 조건

* WHERE의 경우 집계함수를 포함할 경우 오류가 발생한다. 

 

 

+ HAVING을 사용하지 않고 푸는 방법(RANK 함수 이용)

SELECT country, customername Top_customer, sta Top_spent

FROM

(

SELECT country, customername,

sum(totalamount) sta,

rank() over(partition by country order by sum(totalamount) desc) ranking

FROM

(

SELECT c.Country,c.CustomerName,o.TotalAmount

FROM Customers c left join Orders o on c.CustomerID =o.CustomerID

)sb1

group by country, customername

)sb2

where ranking = 1

order by country desc

이건 팀원이 풀고 알려주셨는데 RANK 함수를 사용해 나라별 TotalAmount의 합이 큰 순으로 순위를 매기고 WHERE절을 이용해 가장 큰(1위) 값만 표시되도록 하였다.

RANK함수를 사용하여도 같은 값이 나온다.

 

🥑 회고

이번 레벨부터는 HAVING 함수를 사용하면서 조금 더 복잡하고 어려워 진 것같다🥲 개별의 값을 구하는 것은 어렵지 않지만 그것들을 취합하여 나타내는 과정이 아직 이해가 잘 가지 않고 어려운 것 같다. 짬 날때마다 이해가 되지 않았던 부분들을 다시 풀어봐야겠다.

 

 

반응형