오랑우탄의 반란
LeetCode 리트코드 | 1164. Product Price at a Given Date (MySQL) CTE, DENSE_RANK, UNION 본문
LeetCode 리트코드 | 1164. Product Price at a Given Date (MySQL) CTE, DENSE_RANK, UNION
5&2 2024. 7. 22. 10:51
오늘도 오랑이는 문제를 풉니다.
1164. Product Price at a Given Date
풀이 과정
CTE 를 사용해서 푸는 연습을 해봅니다.
우선 change_date 가 '2019-08-16' 보다 작거나 같은 경우에 대한 조건을 지정해줘야 합니다.
예전 프로그래머스 자동차 대여 문제와 동일한 방식으로 8월 16일에 대해서 1, 아니면 0으로 값을 지정해주고 sum 으로 묶어서 푸는 방식인줄 알았지만, 해당 경우는 8월 16일이 존재하는지 여부가 중요한 것인 반면, 이번 문제는 8월 16일까지의 가장 최신 값과 그 이후에 대한 값은 또 다르게 지정하는 경우여서 각각 분리해서 풀어야 했습니다.
change_date <= '2019-08-16' 에 대한 조건
각 product_id별로 change_date 가 최신값인 행을 구해야 하는 상황에서 그룹별 순위를 매겨주는 rank 함수를 사용합니다.
max(change_date) 을 사용하는 경우 원하는대로 정렬이 날짜별로 제대로 나오지 않기 때문에 rank 윈도우함수로 순위를 확실히 해줍니다.
WITH cte AS
(SELECT *, RANK() OVER (PARTITION BY product_id ORDER BY change_date DESC) AS r
FROM Products
WHERE change_date <= '2019-08-16')
RANK(), DENSE_RANK()
RANK() OVER (PARTITION BY 분류기준 ORDER BY 정렬기준)
# 순위 예시) 1, 1, 1, 4, 5
DENSE_RANK() OVER (PARTITION BY 분류기준 ORDER BY 정렬기준)
# 순위 예시) 1, 1, 1, 2, 3
사용법은 같지만 부여되는 순위가 다른 함수입니다.
RANK 는 동일순위 개수만큼 다음 순위가 증가되는 반면, DENSE_RANK 는 동일순위와 무관하게 다음 순위가 순차적으로 진행됩니다.
이번 문제에서는 어차피 RANK 가 1인 결과값만 필요한 것이기 때문에 둘 중 아무거나 써도 무방합니다.
WITH cte AS
(SELECT *, DENSE_RANK() OVER (PARTITION BY product_id ORDER BY change_date DESC) AS r
FROM Products
WHERE change_date <= '2019-08-16')
SELECT product_id, new_price AS price
FROM cte
WHERE r = 1
change_date > '2019-08-16' 에 대한 조건
그 외 날짜에 대해서는 무조건 10 이 출력되게 해주는 조건을 작성합니다.
앞서 설정한 cte 에 속하지 않은 product_id 에 대해서 10 as price 로 칼럼을 고정값으로 지정해줍니다.
SELECT product_id, 10 AS price
FROM Products
WHERE product_id NOT IN (SELECT product_id FROM cte)
마지막으로 두 테이블을 union 으로 이어줍니다.
최종 코드
WITH cte AS
(SELECT *, DENSE_RANK() OVER (PARTITION BY product_id ORDER BY change_date DESC) AS r
FROM Products
WHERE change_date <= '2019-08-16')
SELECT product_id, new_price AS price
FROM cte
WHERE r = 1
UNION
SELECT product_id, 10 AS price
FROM Products
WHERE product_id NOT IN (SELECT product_id FROM cte)
CTE를 사용하지 않은 풀이는 아래와 같습니다.
UNION 사용은 동일하고 조건이 모두 WHERE절로 들어갑니다.
select distinct product_id, 10 as price
from Products
where product_id not in
(select distinct product_id from Products where change_date <='2019-08-16' )
union
select product_id, new_price as price
from Products
where (product_id, change_date) in
(select product_id , max(change_date) as date from Products
where change_date <='2019-08-16' group by product_id)
오랑우탄이 영어를 하고 오랑이가 쿼리마스터가 되는 그날까지~
https://leetcode.com/problems/product-price-at-a-given-date/description/