🥑 학습내용
사용된 문법&함수 | 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 함수를 사용하면서 조금 더 복잡하고 어려워 진 것같다🥲 개별의 값을 구하는 것은 어렵지 않지만 그것들을 취합하여 나타내는 과정이 아직 이해가 잘 가지 않고 어려운 것 같다. 짬 날때마다 이해가 되지 않았던 부분들을 다시 풀어봐야겠다.
'Data' 카테고리의 다른 글
[아티클스터디] SQL 질문 잘 하는 방법 핵심 요약 (3) | 2024.09.28 |
---|---|
[아티클 스터디] SQL 가독성을 높이는 다섯 가지 사소한 습관 (5) | 2024.09.27 |
[아티클스터디] 데이터 리터리시& 잘못된 데이터 해석 (4) | 2024.09.12 |
[Mysql] SQL 문법연습 풀이 및 해석 (0) | 2024.09.12 |
[아티클스터디] 데이터 분석가는 어떤 일을 하는가? 요약 정리 (3) | 2024.09.06 |