-- 상품이 팔린 첫 해에 관한 레코드 출력
-- 1. 첫 해에 팔린 상품의 sale_id
WITH first_year AS (SELECT sale_id, year
FROM Sales
GROUP BY product_id
HAVING year = MIN(year))
-- Recursive? GROUP BY + HAVING(MIN(year))
SELECT product_id, year as first_year, quantity, price
FROM Sales
WHERE sale_id IN (SELECT sale_id FROM first_year)
| sale_id | product_id | year | quantity | price |
|---|---|---|---|---|
| 1 | 100 | 2008 | 10 | 5000 |
| 2 | 100 | 2009 | 12 | 5000 |
| 7 | 200 | 2011 | 15 | 9000 |
이 test case에서는 통과하는데
다른 test case에서는 아예 output이 출력되지 않았다. CTE에서 year에 관련된 그룹 조건절이 잘못된 건 알겠는데 왜 결과가 출력조자 되지 않았을까?
그룹화를 하고 그 안에서 가장 오래된 행(MIN(year))만 필터링해서 출력한다는 의도를 가지고 CTE를 작성했지만 SQL에서 그렇게 작동되지 않는다.
GROUP BY를 했을 때, 압축을 진행한 후에 HAVING 절로 진입한다.
이때,COUNT함수는 임의의 행을 세는 함수이기 때문에 특정 행을 선정할 필요가 없어 잘 작동하지만 내가 작성한 비교문은 특정 행을 선택해야 하기 때문에 엄격한 SQL에서는 에러가 뜨고 느슨한 SQL에서는 임의로 첫 행을 선택해서 비교한 후 필터링하는 등 생각과는 다르게 작동한다.
WITH first_year AS (SELECT product_id, MIN(year) as 1st_year
FROM Sales
GROUP BY product_id)
SELECT product_id, year as first_year, quantity, price
FROM Sales
WHERE (product_id, year) IN (SELECT product_id, 1st_year FROM first_year)
상품코드와 연도의 조합으로 조건절을 작성하여 진행한다.
다른 방식으로는 Window function이 있다.
WITH year_rnk AS (SELECT product_id, year, quantity, price,
RANK() OVER(PARTITION BY product_id ORDER BY year ASC) as rnk
FROM Sales)
select product_id, year as first_year, quantity, price
from year_rnk
where rnk = 1
둘 다 정답을 제출해보면 B안이 A안보다 많이 느린 것을 알 수 있는데, 이는 CTE에서 B안이 모든 행에서 연도에 관하여 정렬을 하기 때문임을 어렵지 않게 예상할 수 있다.
이때, 데이터가 INDEX로 정렬이 되어있는 상태라면 두 쿼리의 차이는 거의 나지 않을텐데