LeetCode SQL 1321. Restaurant Growth 코드 리뷰 및 분석 (요약)
쿼리
# Write your MySQL query statement below
with DailyTotals as (
select visited_on, sum(amount) as amount
from customer
group by visited_on
)
select dt1.visited_on, sum(dt2.amount) as amount, round(avg(dt2.amount),2) as average_amount
from DailyTotals dt1
join DailyTotals dt2 on dt2.visited_on
between date_sub(dt1.visited_on, interval 6 day) and dt1.visited_on
group by dt1.visited_on having dt1.visited_on >= date_add(min(dt2.visited_on), interval 6 day)
쿼리 분석
- 구조:
WITH
절을 사용하여 일별 매출 합계를 계산하는 공통 테이블 표현식(CTE)DailyTotals
를 정의하고, 이 CTE를 셀프 조인하여 7일간의 이동 합계 및 평균을 계산합니다. DailyTotals
CTE:customer
테이블에서visited_on
으로 그룹화하여 날짜별 총 매출(amount
)을 미리 계산합니다.
- 메인
SELECT
:DailyTotals
CTE를dt1
(기준일)과dt2
(7일 기간 내 날짜)로 셀프 조인합니다.JOIN
조건 (dt2.visited_on BETWEEN DATE_SUB(dt1.visited_on, INTERVAL 6 DAY) AND dt1.visited_on
)을 사용하여 각dt1
기준일에 대해 해당 날짜를 포함한 과거 7일간의 모든dt2
레코드를 연결합니다.GROUP BY dt1.visited_on
을 사용하여 기준일별로 결과를 그룹화합니다.SUM(dt2.amount)
와AVG(dt2.amount)
를 계산하여 7일간의 총 매출 합계와 평균 매출을 구하고,ROUND
함수로 평균값을 소수점 둘째 자리까지 반올림합니다.HAVING dt1.visited_on >= DATE_ADD(MIN(dt2.visited_on), INTERVAL 6 DAY)
조건을 사용하여, 그룹 내에서 최소 7일치의 데이터가 확보된 날짜(dt1.visited_on
)부터 결과를 필터링합니다. 이는 7일 이동 평균/합계를 계산할 수 있는 첫 날부터 결과를 보여주기 위함입니다.
- 결과: 각 해당
visited_on
날짜와 그 날까지의 7일간amount
(총 매출),average_amount
(평균 매출)를 반환합니다.
코드 리뷰
- 정확성: 쿼리는 문제의 요구사항(특정 날짜까지의 7일간 이동 합계 및 평균 계산, 최소 7일 데이터 확보 조건, 반올림)을 논리적으로 정확하게 구현했습니다.
HAVING
절의 조건도 기능적으로는 올바르게 동작하여 시작일을 필터링합니다. - 가독성:
WITH
절(CTE)을 사용하여 쿼리를 단계별로 나누었기 때문에, 일별 집계 로직과 7일 계산 로직이 분리되어 가독성이 좋습니다. 테이블과 컬럼 별칭(dt1
,dt2
등)도 명확합니다. 다만,HAVING
절의 조건 로직은 직관적으로 이해하는 데 약간의 시간이 필요할 수 있습니다. - 효율성: CTE를 통해 일별 집계를 미리 수행하는 것은 효율적입니다. 하지만, 날짜 범위(
BETWEEN
)를 사용한 셀프 조인은DailyTotals
의 행 수에 따라 성능이 크게 저하될 수 있습니다 (N7번 비교 발생 가능). 데이터 양이 많은 경우, *윈도우 함수 (Window Functions:SUM() OVER (...)
,AVG() OVER (...)
)** 를 사용하는 것이 일반적으로 훨씬 효율적이며, 이동 집계를 위한 표준적인 SQL 접근 방식입니다. - 스타일: CTE 사용, 표준 SQL 함수(
SUM
,AVG
,ROUND
,DATE_SUB
,DATE_ADD
,MIN
) 활용 등 일반적인 SQL 작성 스타일에 부합합니다.
한 줄 요약 (Nutshell)
제공된 쿼리는 CTE와 셀프 조인을 활용하여 LeetCode 1321번 문제의 7일 이동 매출 집계 요구사항을 정확히 해결하지만, 대용량 데이터에서는 윈도우 함수를 사용하는 것이 성능상 더 효율적인 대안입니다.
# Write your MySQL query statement below
with DailyTotals as (
select visited_on, sum(amount) as amount
from customer
group by visited_on
),
RollingCalculations AS (
-- 2. 윈도우 함수를 사용하여 7일 이동 합계, 평균, 및 윈도우 내 데이터 수 계산
SELECT visited_on,
-- 현재 행 포함 이전 6개 행(총 7일)의 합계
SUM(amount) OVER (ORDER BY visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS amount,
-- 현재 행 포함 이전 6개 행(총 7일)의 평균
AVG(amount) OVER (ORDER BY visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS average_amount_unrounded,
-- 현재 행 포함 이전 6개 행(총 7일)의 데이터 개수 (7일치 데이터가 있는지 확인용)
COUNT(amount) OVER (ORDER BY visited_on ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS window_days_count
FROM DailyTotals
)
-- 3. 최종 결과 선택 및 필터링
SELECT visited_on, amount,
-- 평균값을 소수점 둘째 자리까지 반올림
ROUND(average_amount_unrounded, 2) AS average_amount
FROM RollingCalculations
-- 윈도우에 정확히 7일치의 데이터가 있는 경우만 결과에 포함
WHERE window_days_count = 7
ORDER BY visited_on; -- 결과를 날짜순으로 정렬
'Algorithm' 카테고리의 다른 글
[16236] 아기 상어 문제 분석 및 리뷰 (0) | 2025.03.30 |
---|---|
[LeetCode SQL] 585: Investments in 2016 - 코드 리뷰 및 분석 (0) | 2025.03.29 |
[LeetCode SQL] 1341: Movie Rating 코드 리뷰 및 분석 (0) | 2025.03.27 |
[16234] 인구 이동 문제 리뷰 및 코드 개선 (0) | 2025.03.22 |
[13460] 구슬 탈출 2 문제 리뷰 및 코드 개선 (0) | 2025.03.04 |