급여 내림차순으로 세 함수를 나란히 놓는다. 급여 3000 은 FORD·SCOTT 둘, 1250 은 MARTIN·WARD 둘이다.
SELECT ENAME, SAL, RANK() OVER (ORDER BY SAL DESC) AS RNK, DENSE_RANK() OVER (ORDER BY SAL DESC) AS DRNK, ROW_NUMBER() OVER (ORDER BY SAL DESC, ENAME) AS RN FROM EMP ORDER BY SAL DESC, ENAME;
위 표의 RANK 마지막 값이 14 인 것은 EMP 를 급여 내림차순으로 세웠을 때 맨 뒤(SMITH, 800)에 동점이 없기 때문이다. 맨 뒤 값이 동점이면 마지막 순위는 행 수보다 작다. 20번 부서를 급여 오름차순으로 세우면 FORD·SCOTT 이 3000 으로 함께 4위이고 행은 5개다.
DENSE_RANK 의 마지막 값은 서로 다른 값의 개수다. EMP 의 급여 종류는 12가지다.
순위 함수는 무엇을 기준으로 줄을 세울지 알아야 한다. OVER () 처럼 비워 두면 오류다.
SELECT ENAME, SAL, RANK() OVER () AS RNK FROM EMP WHERE DEPTNO = 10;
SELECT ENAME, SAL, RANK() OVER () AS RNK FROM EMP WHERE DEPTNO = 10 *ERROR at line 1:ORA-30485: missing ORDER BY expression in the window specification
ROW_NUMBER 도 Oracle 에서는 같은 ORA-30485 가 난다.
SUM·AVG 같은 집계형 윈도우 함수는 OVER () 를 받는다. 전체 행을 한 파티션으로 보고 같은 값을 붙인다(Day 2).
SELECT ENAME, SAL, RANK() OVER (ORDER BY SAL DESC) AS RNK FROM EMP WHERE RANK() OVER (ORDER BY SAL DESC) <= 3;
SELECT ENAME, SAL, RANK() OVER (ORDER BY SAL DESC) AS RNK FROM EMP WHERE RANK() OVER (ORDER BY SAL DESC) <= 3 *ERROR at line 1:ORA-30483: window functions are not allowed here
HAVING 도 마찬가지다.
SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING RANK() OVER (ORDER BY COUNT(*) DESC) = 1;
SELECT DEPTNO, COUNT(*) FROM EMP GROUP BY DEPTNO HAVING RANK() OVER (ORDER BY COUNT(*) DESC) = 1 *ERROR at line 1:ORA-30483: window functions are not allowed here
해법은 W5 Day 2 의 인라인 뷰다. 안쪽에서 순위를 계산해 열로 만들고, 바깥 WHERE 에서 그 열을 거른다.
SELECT ENAME, SAL, RNK FROM (SELECT ENAME, SAL, RANK() OVER (ORDER BY SAL DESC) AS RNK FROM EMP) WHERE RNK <= 3 ORDER BY RNK, ENAME;
안쪽 SELECT 가 끝나면 RNK 는 평범한 열이다. 바깥 WHERE 는 그 열을 비교할 뿐이다.
같은 SELECT 의 별칭 RNK 를 WHERE 에 써도 안 된다. WHERE 가 SELECT 보다 먼저 처리되기 때문이다(ORA-00904).
부서별 상위 2명도 같은 방법이다. 동점이어도 딱 2명씩 받으려면 ROW_NUMBER 를 쓴다.
SELECT DEPTNO, ENAME, SAL FROM (SELECT DEPTNO, ENAME, SAL, ROW_NUMBER() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC, ENAME) AS RN FROM EMP) WHERE RN <= 2 ORDER BY DEPTNO, RN;
DEPTNO ENAME SAL---------- ---------- ---------- 10 KING 5000 10 CLARK 2450 20 FORD 3000 20 SCOTT 3000 30 BLAKE 2850 30 ALLEN 1600
조건
고를 함수
20번 부서 결과 (<= 2)
동점은 모두 포함
RANK 또는 DENSE_RANK
FORD·SCOTT (둘 다 1위)
정확히 n 명
ROW_NUMBER (+ 동점 가를 키)
FORD·SCOTT (1번·2번)
3위 급여까지 모두
DENSE_RANK <= 3
FORD·SCOTT·JONES·ADAMS
20번은 우연히 결과가 같다. <= 1 로 바꾸면 RANK 는 둘, ROW_NUMBER 는 하나를 돌려준다.
윈도우 함수 : 행을 합치지 않고 행마다 계산 값을 붙이는 함수. OVER 절이 붙는다. 분석 함수라고도 부른다.
파티션 : PARTITION BY 로 나눈 묶음. 윈도우 함수는 파티션마다 따로 계산한다.
RANK : 동점에 같은 순위를 주고, 다음 순위는 동점 수만큼 건너뛴다(1, 2, 2, 4).
DENSE_RANK : 동점에 같은 순위를 주고, 다음 순위를 건너뛰지 않는다(1, 2, 2, 3).
ROW_NUMBER : 동점이어도 1부터 하나씩 다른 번호를 준다. 동점 사이 순서는 두 번째 정렬 키로 정한다.
ORA-30483 : WHERE·HAVING·GROUP BY 처럼 윈도우 함수를 쓸 수 없는 자리에 썼을 때의 오류.
ORA-30485 : 순위 함수의 OVER 안에 ORDER BY 가 없을 때의 오류.
인라인 뷰 : FROM 절의 서브쿼리. 순위를 열로 만든 뒤 바깥에서 거를 때 쓴다.
📝 연습 문제
선택지를 클릭하면 정답·해설이 펼쳐집니다.
문제 1
SELECT ENAME, DENSE_RANK() OVER (ORDER BY SAL DESC) AS DR FROM EMP; 에서 JONES(급여 2975)의 DR 값은? (급여 상위는 KING 5000, FORD·SCOTT 3000, JONES 2975 순이다)
문제 2
다음 중 Oracle 에서 오류가 나는 SQL 은?
문제 3
급여 내림차순으로 번호를 매길 때, 급여가 같은 FORD 와 SCOTT 에게도 서로 다른 번호를 주는 함수는?
문제 4
SELECT ENAME, RANK() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS RNK FROM EMP; 에서 30번 부서 WARD(1250)의 RNK 는? (30번 급여: BLAKE 2850, ALLEN 1600, TURNER 1500, MARTIN 1250, WARD 1250, JAMES 950)
문제 5
SELECT ENAME, RANK() OVER (ORDER BY SAL DESC) AS RNK FROM EMP WHERE DEPTNO = 20; 에서 JONES 의 RNK 는? (20번: FORD 3000, SCOTT 3000, JONES 2975, ADAMS 1100, SMITH 800. 전체 1위 KING 은 10번이다)