2월 28, 2024

[PostgreSQL/SQL] partition by 사용하여 그룹별 순위 매기는 방법, rank(), dense_rank(), row_number() 차이점

1. SQL에서 순위를 매기는 방법

SQL에서 GROUP 별로 순위를 매기고자 할 때 PARTITION BY와 ORDER BY를 사용하여 그룹별 순서를 매길 수 있다. 
대표적인 예시로 

SELECT RANK() OVER (PARTITION BY [그룹화할 칼럼들] ) ORDER BY [순서 정렬할 칼럼들] DESC) AS RANK, * 
FROM [테이블명] A ;


위 SQL이 있을 수 있는데 여기서 가장 먼저 나오는 RANK() 이외에도 DENSE_RANK(), ROW_NUMBER()를 사용할 수 있고 오늘은 이들 각각의 공통점과 차이점에 대하여 알아보겠다. 

1) RANK()

SELECT RANK() OVER (PARTITION BY [그룹화할 칼럼들] ) ORDER BY [순서 정렬할 칼럼들] DESC) AS RANK, * 
FROM [테이블명] A ;


PARTITION BY 뒤에 나오는 칼럼들로 그룹화를 한다. 그리고 동일한 RANK가 있으면 그 다음 순위로 바로 넘어간다. 예를 들어 아래와 같이

SELECT RANK() OVER (PARTITION BY TEAM ORDER BY AGE DESC) AS RANK, * 
FROM 테이블;

과 같은 SQL이 있다고 가정해보자.
그러면 TEAM으로 그룹을 나누고 AGE로 순위를 매긴다. 그리고 RANK()의 특징은 그 전 같은 순위의 값들을 모두 다른 RANK로 간주하고 다음의 숫자로 다음 RANK가 매겨진 다는 것이다. 
예를 들면 1등이 3명 있다면 다음 RANK는 4부터 시작하는 형식이다. 

여기서도 같은 GROUP인 (TEAM에 의해서 PARTITION BY됨) A에서 RANK 1이 2명 있으므로 그 다음 A GROUP의 사람은 RANK 3을 배정받는 것이다. 

2) DENSE_RANK() 

DENSE_RANK()는 RANK()와 유사하지만 동일 RANK가 있을 경우 다음 RANK를 정하는 방식만 다르다. 이전 순위의 중복값의 개수와 상관없이 다음 숫자로 RANK를 매긴다. 


위 예시에서는 


A 그룹의 2등이 숫자 3이 아니라 2로 배정된 다는 것을 알 수 있다. 

즉 같은 AGE가 있을 경우 모두 다 같은 RANK로 간주하고, 그 다음 순위는 그 전 순위에 동차가 있더라도 바로 다음 숫자로 넘어간다. 예를 들어 1등이 3명이더라도 다음 순위는 2등으로 배정된다는 것이 DENSE_RANK()의 특징이다. 


3) ROW_NUMBER()

ROW_NUMBER()는 DENSE_RANK()에서 나아가 해당 칼럼의 동일값이 있어도 아예 중복값을 허용하지 않는 것이다. 즉 위 DENSE_RANK()에서는 ORDER BY AGE에 의해서 AGE라는 칼럼 데이터가 같으면 동일 RANK로 배정을 했는데 ROW_NUMBER()에서는 이것도 허용하지 않는 것이다.