홍동이의 성장일기

[LeetCode] 1321. Restaurant Growth 본문

Tool/SQL 코딩테스트 풀이

[LeetCode] 1321. Restaurant Growth

홍동2 2023. 8. 24. 22:18

 

Restaurant Growth - LeetCode

Can you solve this real interview question? Restaurant Growth - Table: Customer +---------------+---------+ | Column Name | Type | +---------------+---------+ | customer_id | int | | name | varchar | | visited_on | date | | amount | int | +---------------+

leetcode.com

 

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 데이터 분석 캠프 실전반' 을 수강하며 작성한 내용입니다.

728x90
Comments