본문 바로가기
Algorithm/SQL

Leetcode SQL 50 - 1321. Restaurant Growth

by 호찌민 2024. 3. 23.

문제 사이트: @leetcode

Table: Customer

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| customer_id   | int     |
| name          | varchar |
| visited_on    | date    |
| amount        | int     |
+---------------+---------+
In SQL,(customer_id, visited_on) is the primary key for this table.
This table contains data about customer transactions in a restaurant.
visited_on is the date on which the customer with ID (customer_id) has visited the restaurant.
amount is the total paid by a customer.

 

You are the restaurant owner and you want to analyze a possible expansion (there will be at least one customer every day).

Compute the moving average of how much the customer paid in a seven days window (i.e., current day + 6 days before). average_amount should be rounded to two decimal places.

Return the result table ordered by visited_on in ascending order.

 

<나의 정답 쿼리>

SELECT *
FROM 
    (
    SELECT 
        A.visited_on
        ,SUM(amount) OVER (ORDER BY visited_on ROWS BETWEEN
                        6 PRECEDING AND CURRENT ROW) AS amount
        ,ROUND(AVG(amount) OVER (ORDER BY visited_on ROWS BETWEEN
                        6 PRECEDING AND CURRENT ROW), 2) AS average_amount
    FROM
    (
        SELECT 
            visited_on
            ,SUM(amount) AS amount
        FROM Customer
        GROUP BY visited_on
    ) A
) B
WHERE B.visited_on >= (SELECT MIN(visited_on) + interval '6 days' FROM Customer)
ORDER BY B.visited_on

 

 

내가 생각한 문제 풀이 순서

  1. 첫번째 Subquery 내에서 일 별로 Amount 구하기 (하루에 여러 손님이 방문할 수 있으므로 일 별로 계산)
  2. 두번째 Window 함수를 통해 일자별 최근 7일에 대한 SUM(amount)와 AVG(amount) 구하기 (1번째 순서에서 일별로 계산해두었으므로)
  3. 최소 일자보다 6일 뒤인 날짜부터 결과를 나올 수 있도록 하기 (1/1 부터 시작하는 테이블이 있다고 시작할 때, 1/1은 하루치 이므로 최소 테이블에서 최근 1주일치를 가지고 있는 날짜부터 시작하기 위해)

내가 개선하고 싶었던 점

  • 서브 쿼리를 최소화 할 수 없을까,,,, 생각.

<타인이 작성한 쿼리 참고>

SELECT
    visited_on,
    (
        SELECT SUM(amount)
        FROM customer
        WHERE visited_on BETWEEN DATE_SUB(c.visited_on, INTERVAL 6 DAY) AND c.visited_on
    ) AS amount,
    ROUND(
        (
            SELECT SUM(amount) / 7
            FROM customer
            WHERE visited_on BETWEEN DATE_SUB(c.visited_on, INTERVAL 6 DAY) AND c.visited_on
        ),
        2
    ) AS average_amount
FROM customer c
WHERE visited_on >= (
        SELECT DATE_ADD(MIN(visited_on), INTERVAL 6 DAY)
        FROM customer
    )
GROUP BY visited_on;

 

 

<타인이 작성한 쿼리의 의도 파악>

  • 내가 3번에서 생각한 것을 WHERE 절에 우선 주어서 1/7부터 시작하게 만듦
  • 위 조건의 날짜로부터 - 6 days 하고 현재 날짜까지 구할 수 있는 형태를 서브쿼리로 만듦
    • 훨씬 더 깔끔하다고 느낌