홍동이의 성장일기
[LeetCode] 1321. Restaurant Growth 본문
WITH cte_sum AS(
SELECT visited_on
, SUM(amount) as sum_amount
FROM customer
GROUP BY visited_on
)
, cte_all AS(
SELECT visited_on
, SUM(sum_amount) OVER w AS amount
, ROUND(SUM(sum_amount) OVER w / 7, 2) AS average_amount
FROM cte_sum
WINDOW w AS (ORDER BY visited_on RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW)
)
SELECT visited_on, amount, average_amount
FROM cte_all
WHERE visited_on >= (SELECT DATE_ADD(MIN(visited_on), INTERVAL 6 DAY)
FROM customer)
ORDER BY visited_on
💡 문제 풀이
이번 문제는 풀면서 고민을 많이해서 풀이가 길다.
1. visited_on별 amount의 합계를 구해준다.
SELECT visited_on
, SUM(amount) as sum_amount
FROM customer
GROUP BY visited_on
➡️ 같은 날의 데이터가 여러 개 있는 날도 있어서 GROUP BY를 해주어야 한다.
2. 현재 날짜의 amount + 이전 6일의 amount의 합계와 평균을 구해준다.
SELECT visited_on
, SUM(sum_amount) OVER w AS amount
, ROUND(SUM(sum_amount) OVER w / 7, 2) AS average_amount
FROM cte_sum
WINDOW w AS (ORDER BY visited_on RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW)
➡️ 배운내용을 활용해보고 싶어서 Named Window를 사용해보았다. w 자리에 (ORDER BY visited_on RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW) 가 들어가는 것이다.
2-1. RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW
수업시간에 배웠던 ROWS BETWEEN 6 PRECEDING AND CURRENT ROW로는 해결할 수 없는 문제였다. 우리는 앞 6행이 필요한 것이 아니라 앞 6일의 값이 필요하기 때문이다.
➡️ Solutions를 돌아다니다보니 ROWS를 RANGE로, 6을 INTERVAL 6 DAY로 바꿔주면 현재 행과 이전 6일 사이의 작업을 처리할 수 있는 윈도우 쿼리를 만들 수 있다.
2-2. SUM(sum_amount) OVER w / 7 ➡️ SUM과 AVG의 차이
2-1와 같은 맥락으로 이어지는 문제다.
마지막 Test Case에서 average_amount를 구하는 부분이 결과값이 달라서 애를 먹었다😥
왜 합계는 결과가 잘 나왔는데 평균은 다르게 나온거지? 🤔
결과를 보니 1월 2, 3일의 데이터가 비어있는 부분이 있다는 것을 확인할 수 있었다.
아! 그럼 평균이 구해질 때 7일이 다 반영이 안되었나보다!
1/7 에는 (1,4,5,6,7을 다 더한 값) / 5
1/8 에는 (1,4,5,6,7,8을 다 더한 값) / 6
1/9 에는 (1,4,5,6,7,8,9을 다 더한 값) / 7
이렇게 되었다는거지?
근데 우리는 7일의 평균을 구해야하기 때문에 모든 합계가 7로 나누어져야 한다.
'이 문제를 어떻게 해결하면 좋을까..' 하고 곰곰히 생각하다가
이전에 데이터리안 강의를 들으면서 해당 부분에 관한 이야기를 배웠는데
잘 이해가 가지 않아 다시 한 번 질문했던 것이 떠올랐다.
나는 처음에 AVG(sum_amount) OVER w AS average_amount 즉, AVG 집계함수를 사용했으니 이 문제가 맞는 것 같다고 판단하였다. 그래서 데이터의 합계를 7로 나누는 방법을 선택하니 문제가 해결되었다.
3. visited_on의 범위 정해주기
SELECT visited_on, amount, average_amount
FROM cte_all
WHERE visited_on >= (SELECT DATE_ADD(MIN(visited_on), INTERVAL 6 DAY)
FROM customer)
ORDER BY visited_on
➡️ 우리는 모든 날짜의 결과가 아닌 최소 이전 6일의 정보가 반영된 데이터를 보고 싶다. 이를 위해 visited_on의 최솟값 (손님의 최초 방문일) + 6일보다 크거나 같은 행만 나올 수 있도록 WHERE절을 지정해주었다.
이번 문제는 꼭 사용해서 풀고 싶었던 함수가 있어서 Solutions를 봐도 완벽한 해답을 찾기 힘들었다.
날짜 함수를 제일 다루기 어려워하는 나에게는 쉽지 않은 문제였다😅
여러 개의 Solutions를 통해 필요한 부분만 내 코드로 가져오고,
그동안 배웠던 지식들을 총 집합하여 풀어본 데이터리안 마지막 과제였다!
해결하고나니 너무 뿌듯했다.
📍본 내용은 데이터리안 'SQL 데이터 분석 캠프 실전반' 을 수강하며 작성한 내용입니다.
'Tool > SQL 코딩테스트 풀이' 카테고리의 다른 글
[HackerRank] Contest Leaderboard (1) | 2023.09.16 |
---|---|
[HackerRank] Weather Observation Station 17 (0) | 2023.09.16 |
[LeetCode] 178. Rank Scores (0) | 2023.08.24 |
[LeetCode] 185. Department Top Three Salaries (0) | 2023.08.23 |
[LeetCode] 511. Game Play Analysis I (0) | 2023.08.22 |