이 문제는 각 사용자별 우버 거래내역 중에서 세 번째 거래 내역을 조회하는 문제이다.
세 번째 거래 내역을 조회해야되기 때문에 사용자별로 거래 시간(transaction_date)를 정렬해줘야 된다.
위에서 말했 듯이 여기서 중요한 점이 전체 데이터에서 3번째를 찾는 것이 아니고
각 사용자별로 3번째 거래 내역을 찾아야 한다는 점이다.
찾는 방법 순서는 다음과 같다.
1. 사용자별로 그룹을 나눈다.
2. 거래 시간 기준으로 정렬을 수행한다.
3. 순서를 매겨준다.
4. 매겨진 순서 중에서 3번째만 고른다.
그룹을 나누고, 순서를 매겨주기 위해서 윈도우 함수와 파티션 함수를 사용해 주어야 한다.
SELECT user_id, spend, transaction_date
FROM (
SELECT user_id,
spend,
transaction_date,
ROW_NUMBER () OVER (
PARTITION BY user_id
ORDER BY transaction_date
) as row_num
FROM transactions
) a
WHERE a.row_num = 3
;
윈도우 함수란 GROUP BY와 달리 행을 그룹화하지 않고, 테이블의 기존 행은 유지하면서 특정 범위 내에서 순위, 합계, 평균 등을 계산하여 각 행에 결과를 반환하는 함수다.
OVER 절을 사용해 데이터를 파티션하고 정렬하여 행 끼리의 관계를 분석한다.
일반적인 집계 함수인 GROUP BY와 간단하게 차이점을 살펴 본다면 다음과 같다.
SELECT user_id, spend, transaction_date, COUNT(*)
FROM transactions
GROUP BY user_id;

GROUP BY를 사용하게되면 사용자별로 거래 횟수는 셀 수 있지만
원래 테이블의 정보들은 확인할 수 없게 된다.
SELECT user_id, spend, transaction_date,
COUNT(*) OVER (
PARTITION BY user_id
)
FROM transactions;

윈도우 함수를 사용하게되면 사용자별로 정보들을 유지하면서 계산 결과도 확인이 가능하다.
ROW_NUMBER()는 각 행에 순서를 매겨주는 윈도우 함수다.
예를 들어서 어떤 사용자의 거래가 3건이 있는 경우 정렬 기준을 주면 그 기준에 맞춰서 1, 2, 3과 같은 번호를 붙여주는 것이다.
윈도우 함수의 형태는 다음과 같다.
윈도우함수() OVER (
PARTIION BY 기준컬럼
ORDER BY 정렬기준컬럼 [AES/DES]
)
PARTITION BY는 윈도우 함수에서 데이터를 특정 기준에 따라 여러 파티션으로 나누는 함수이다.
GROUP BY와 달리 원본 행을 유지하면서 각 그룹 내에서 순위, 합계, 평균 등을 계산할 수 있게 해준다.
문제에서 사용한 PARTITION BY user_id의 의미는 user_id가 같은 행끼리 하나의 그룹으로 파티션을 나누는 것이다.
이 문제를 풀 때 꼭 정렬을 해주어야 한다. ROW_NUMBER() 함수는 순번을 붙이는 함수이기 때문에 어떤 기준을 가지고 정렬을 할지가 있어야되기 때문이다.
세 번째 거래를 찾아야 되기 때문에 거래 시간을 기준으로 정렬을 해주는 것이 중요하다.
윈도우 함수로 만들어낸 컬럼은 같은 SELECT문 안에서 WHERE 조건을 적용하여 바로 사용할 수 없다.(쿼리 실행 순서)
SQL문은 작성 순서대로 실행되는 것이 아니고 실행 순서가 정해져 있다.
1. FROM
2. WHERE
3. GROUP BY
4. HAVING
5. SELECT
+ 추가
6. WINDOW FUNCTION
7. ORDER BY
윈도우 함수는 SELECT 단계 이후에 계산된다.
그래서 먼저 서브쿼리를 만들어서 컬럼을 만든 뒤, 바깥쿼리에서 만들어낸 컬럼에 대한 조건을 적용한 것이다.
