만족

[MYSQL] RANK/DENSE_RANK/ROW_NUMBER 함수 본문

[MYSQL] RANK/DENSE_RANK/ROW_NUMBER 함수

DataBase/mysql Satisfaction 2021. 3. 3. 17:39

RANK/DENSE_RANK/ROW_NUMBER 함수는 모두 특정 열의 값에 대해 순위를 매기는 함수다.

 

서식은 다음과 같다

 

RANK() OVER([PARTITION BY COL_NAME_1] ORDER BY COL_NAME_2 [DESC])

 

RANK대신 DENSE_RANK/ROW_NUMBER로 대치해서 사용할 수 있다.

[...]로 된 부분은 생략 가능하다.

 

다른 함수들과 달리 꽤나 괴상하게 생긴 함수인데, 그렇게 어려운 부분은 없으니 겁먹지 않아도 된다.

 

먼저 [PARTITION BY COL_NAME_1] 부분 없이 알아보자.

 

RANK() OVER (ORDER BY COL_NAME_2 DESC)

COL_NAME_2값을 내림차순으로 순위를 매기는 함수다.

 

즉 다음과 같은 데이터가 있다고 해보자.

 

departmemt_id name salary
1 jane 2000
1 sam 3000
2 micheal 4000

<<Salary Table>>

 

여기서 다음과 같은 쿼리를 실행한다.

 

SELECT name, RANK() OVER (ORDER BY salary) AS salary_rank FROM Salary;

 

name salary_rank
jane 3
sam 2
micheal 1

그러면 위와 같은 결과를 얻을 수 있다.

 

salary 열 값에 따라 내림차순으로 순위를 매기므로

가장 높은 micheal이 1순위고, 가장 낮은 jane이 3순위가 된다.

 

그렇다면 DENSE_RANK/ROW_NUMBER와 RANK의 차이점은 뭘까?

RANK 공동 순위만큼 건너뜀 (ex: 1,2,2,4 ...)
DENSE_RANK 공동 순위를 뛰어넘지 않음 (ex: 1,2,2,3 ...)
ROW_NUMBER 공동 순위를 무시함 (ex: 1,2,3,4 ...)

가령 salary가 (2000,3000,3000,4000) 라고 할 때,

RANK를 사용하면 (4,2,2,1)이 출력되고

DENSE_RANK는 (3,2,2,1)이,

ROW_NUMBER는 (4,3,2,1)이 출력된다.

 

PARTITION BY COL_NAME

departmemt_id name salary
1 jane 2000
1 sam 3000
2 micheal 4000

마찬가지로 Salary 테이블에서 salary순으로 출력하고 싶은데,

부서별로 순위를 각각 매기고 싶을 때 PARTITION BY COL_NAME 을 사용한다.

 

위의 요구사항을 위해 다음 쿼리를 작성할 수 있다.

 

SELECT name, RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS salary_rank FROM Salary;

name salary_rank
jane 2
sam 1
micheal 1

결과로 위를 얻을 수 있다.

 

department_id별로 순위를 따로 매기기 때문에,

department_id가 1인 jane과 sam끼리만 순위를 매기게 되어,

sam이 1, jane이 2를 얻게 된다.

 

주의할 점

salary_rank를 WHERE 문에서 사용하면 '열을 찾을 수 없다'는 오류가 발생한다.

(Unknown column 'salary_rank' in 'where clause')

 

가령

SELECT name, RANK() OVER (ORDER BY salary) AS salary_rank FROM Salary WHERE salary_rank=1;

위와 같이 실행하면 오류가 발생한다.

 

Salary 테이블에는 salary_rank 열이 존재하지 않기 때문에 발생하는데, 이 때는 서브쿼리를 이용해 salary_rank를 먼저 뽑아낸 후,

메인 쿼리에서 salary_rank를 필터링한다.

 

SELECT * FROM (

  SELECT name, RANK() OVER (ORDER BY salary) AS salary_rank FROM Salary

) Salary_rank

WHERE salary_rank = 1;

 

이렇게 하면 Salary_rank라는 뷰는 salary_rank라는 열을 가지고 있기 때문에 정상적으로 출력된다.

'DataBase > mysql' 카테고리의 다른 글

[MYSQL] 조인(JOIN)  (0) 2021.04.26
[MYSQL] Aggregtion(집계)과 GROUP(그룹)  (0) 2021.04.26
[MYSQL] 셀렉트(SELECT) - 2  (0) 2021.04.26
[MYSQL] 셀렉트(SELECT) - 1  (0) 2021.04.26
[MYSQL] SQL CREATE/DROP/ALTER  (0) 2021.04.25


Comments