📚 Study/Oracle
Oracle :: 순위 관련 함수(RANK(), DENS_RANK(), RANK함수 사용 없이 순위 구하기)
bono-hye
2023. 10. 25. 22:15
(파일명 : 20231024_01_scott)
■ RANK()
- RANK() OVER(OREDER BY 컬럼명 ASC(생략가능)/ DESC)
- 그룹별로 순위를 반환하고 싶을 때!
RANK() OVER(PARTITION BY 컬럼명 ORDER BY 컬럼명 ASC/DESC)
- 순위 반환.
- 만약 공동 1등일 경우 2등은 2가 아닌 3을 반환함!!
--○ RANK() → 등수(순위)를 반환하는 함수
SELECT EMPNO "사원번호", ENAME "사원명", DEPTNO "부서번호", SAL "급여"
, RANK() OVER(ORDER BY SAL DESC) "전체급여순위"
FROM EMP;
--==>>
/*
7839 KING 10 5000 1
7902 FORD 20 3000 2
7788 SCOTT 20 3000 2
7566 JONES 20 2975 4
7698 BLAKE 30 2850 5
7782 CLARK 10 2450 6
7499 ALLEN 30 1600 7
7844 TURNER 30 1500 8
7934 MILLER 10 1300 9
7521 WARD 30 1250 10
7654 MARTIN 30 1250 10
7876 ADAMS 20 1100 12
7900 JAMES 30 950 13
7369 SMITH 20 800 14
*/
SELECT EMPNO "사원번호", ENAME "사원명", DEPTNO "부서번호", SAL "급여"
, RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "부서별급여순위"
, RANK() OVER(ORDER BY SAL DESC) "전체급여순위"
FROM EMP;
--==>>
/*
7839 KING 10 5000 1 1
7902 FORD 20 3000 1 2
7788 SCOTT 20 3000 1 2
7566 JONES 20 2975 3 4
7698 BLAKE 30 2850 1 5
7782 CLARK 10 2450 2 6
7499 ALLEN 30 1600 2 7
7844 TURNER 30 1500 3 8
7934 MILLER 10 1300 3 9
7521 WARD 30 1250 4 10
7654 MARTIN 30 1250 4 10
7876 ADAMS 20 1100 4 12
7900 JAMES 30 950 6 13
7369 SMITH 20 800 5 14
*/
SELECT EMPNO "사원번호", ENAME "사원명", DEPTNO "부서번호", SAL "급여"
, RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "부서별급여순위"
, RANK() OVER(ORDER BY SAL DESC) "전체급여순위"
FROM EMP
ORDER BY DEPTNO;
--==>>
/*
7839 KING 10 5000 1 1
7782 CLARK 10 2450 2 6
7934 MILLER 10 1300 3 9
7902 FORD 20 3000 1 2
7788 SCOTT 20 3000 1 2
7566 JONES 20 2975 3 4
7876 ADAMS 20 1100 4 12
7369 SMITH 20 800 5 14
7698 BLAKE 30 2850 1 5
7499 ALLEN 30 1600 2 7
7844 TURNER 30 1500 3 8
7654 MARTIN 30 1250 4 10
7521 WARD 30 1250 4 10
7900 JAMES 30 950 6 13
*/
■ DENS_RANK()
- DENE_RANK() OVER(OREDER BY 컬럼명 ASC(생략가능)/ DESC)
- 서열을 반환하는 함수
- 공동 1등이더라도 2등은 2를 반환함
--○ DENSE_RANK() → 서열을 반환하는 함수
SELECT EMPNO "사원번호", ENAME "사원명", DEPTNO "부서번호", SAL "급여"
, DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) "부서별급여서열"
, DENSE_RANK() OVER(ORDER BY SAL DESC) "전체급여서열"
FROM EMP
ORDER BY 3, 4 DESC;
--==>>
/*
7839 KING 10 5000 1 1
7782 CLARK 10 2450 2 5
7934 MILLER 10 1300 3 8
7902 FORD 20 3000 1 2
7788 SCOTT 20 3000 1 2
7566 JONES 20 2975 2 3 -- 내 앞이 공동 1위더라도 3이 아닌 2를 반환한다.!
7876 ADAMS 20 1100 3 10
7369 SMITH 20 800 4 12
7698 BLAKE 30 2850 1 4
7499 ALLEN 30 1600 2 6
7844 TURNER 30 1500 3 7
7654 MARTIN 30 1250 4 9
7521 WARD 30 1250 4 9
7900 JAMES 30 950 5 11
*/
■ RANK 활용 문제 풀이 1
--○ EMP 테이블의 사원 데이터를
-- 사원명, 부서번호, 연봉, 부서내연봉순위, 전체연봉순위 항목으로 조회한다.
SELECT ENAME"사원명", DEPTNO"부서번호", SAL*12+NVL(COMM,0)"연봉"
, RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL*12+NVL(COMM,0) DESC) "부서내연봉순위"
, RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC) "전체연봉순위"
FROM EMP;
--==>>
/*
KING 10 60000 1 1
FORD 20 36000 1 2
SCOTT 20 36000 1 2
JONES 20 35700 3 4
BLAKE 30 34200 1 5
CLARK 10 29400 2 6
ALLEN 30 19500 2 7
TURNER 30 18000 3 8
MARTIN 30 16400 4 9
MILLER 10 15600 3 10
WARD 30 15500 5 11
ADAMS 20 13200 4 12
JAMES 30 11400 6 13
SMITH 20 9600 5 14
*/
SELECT T.사원명, T.부서번호
, RANK() OVER(PARTITION BY T.부서번호 ORDER BY T.연봉 DESC) "부서내연봉순위"
, RANK() OVER(ORDER BY T.연봉 DESC) "전체연봉순위"
FROM
(
SELECT ENAME"사원명", DEPTNO"부서번호", SAL*12+NVL(COMM,0) "연봉"
FROM EMP
)T
ORDER BY 2,4;
--==>> 서브쿼리 활용
/*
KING 10 60000 1 1
CLARK 10 29400 2 6
MILLER 10 15600 3 10
FORD 20 36000 1 2
SCOTT 20 36000 1 2
JONES 20 35700 3 4
ADAMS 20 13200 4 12
SMITH 20 9600 5 14
BLAKE 30 34200 1 5
ALLEN 30 19500 2 7
TURNER 30 18000 3 8
MARTIN 30 16400 4 9
WARD 30 15500 5 11
JAMES 30 11400 6 13
*/
■ RANK 활용 문제 풀이 2
- WHERE 절에 RANK() 쓸 수 없음!
--○ EMP 테이블에서 전체연봉순위가 1등 부터 5등 까지만
-- 사원명, 부서번호, 연봉, 전체연봉순위 항목으로 조회한다.
-- 내가 한 풀이
SELECT F.*
FROM
(
SELECT T.*, RANK() OVER(ORDER BY T.연봉)"전체연봉순위"
FROM
(
SELECT ENAME"사원명", DEPTNO"부서번호", SAL*12+NVL(COMM,0)"연봉"
FROM EMP
)T
)F
WHERE F.전체연봉순위<6;
-- 같이 한 풀이
SELECT 사원명, 부서번호, 연봉, 전체연봉순위
FROM EMP
WHERE 전체연봉순위가 1등 부터 5등;
SELECT ENAME "사원명", DEPTNO "부서번호", SAL*12+NVL(COMM,0)"연봉"
, RANK() OVER(ORDER BY (연봉) DESC) "전체연봉순위"
FROM EMP
WHERE 전체연봉순위가 1등 부터 5등;
SELECT ENAME "사원명", DEPTNO "부서번호", SAL*12+NVL(COMM,0)"연봉"
, RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC) "전체연봉순위"
FROM EMP
WHERE RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC)가 1등 부터 5등;
SELECT ENAME "사원명", DEPTNO "부서번호", SAL*12+NVL(COMM,0)"연봉"
, RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC) "전체연봉순위"
FROM EMP
WHERE RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC) <= 5;
--==>> 에러 발생
-- (ORA-30483: window functions are not allowed here)
--※ 위의 내용은 RANK() OVER() 함수를 WHERE 조건절에서 사용한 경우이며
-- 이 함수는 WHERE 조건절에서 사용할 수 없기 때문에 발생하는 에러이다.
-- 이 경우, 우리는 INLINE VIEW 를 활용해서 풀이해야 한다.
SELECT T.*
FROM
(
SELECT ENAME "사원명", DEPTNO "부서번호", SAL*12+NVL(COMM,0)"연봉"
, RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC) "전체연봉순위"
FROM EMP
)T
WHERE T.전체연봉순위 <= 5;
--==>>
/*
KING 10 60000 1
SCOTT 20 36000 2
FORD 20 36000 2
JONES 20 35700 4
BLAKE 30 34200 5
*/
■ RANK 활용 문제 풀이 3
--○ EMP 테이블에서 각 부서별로 연봉 등수가 1등 부터 2등 까지만 조회한다.
-- 사원명, 부서번호, 연봉, 부서내연봉등수, 전체연봉등수 항목을
-- 조회할 수 있도록 쿼리문을 구성한다.
-- 내가 한 풀이 (서브쿼리 1번 사용)
SELECT T.*
FROM
(
SELECT ENAME"사원명", DEPTNO"부서번호", SAL*12+NVL(COMM,0)"연봉"
, RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL*12+NVL(COMM,0))"부서내연봉등수"
, RANK() OVER(ORDER BY SAL*12+NVL(COMM,0))"전체연봉등수"
FROM EMP
)T
WHERE T.부서내연봉등수 <= 2;
-- 서브쿼리 2번 사용
SELECT F.*
FROM
(
SELECT T.*
, RANK() OVER(PARTITION BY T.부서번호 ORDER BY T.연봉)"부서내연봉등수"
, RANK() OVER(ORDER BY T.연봉)"전체연봉등수"
FROM
(
SELECT ENAME"사원명", DEPTNO"부서번호", SAL*12+NVL(COMM,0)"연봉"
FROM EMP
)T
)F
WHERE F.부서내연봉등수 <= 2;
(파일명 20231025_01_soctt)
■ RANK함수 사용 없이 순위 구하기
- 하위 버전에서는 RANK()나 DENSE_RANK()를 사용할 수 없음!
--RANK() / DENSE_RANK()
--> ORACLE 9i 부터 적용... (MSSQL 2005 부터 적용...(?) 확실하지는 않음)
--> 하위 버전에서는 RANK()나 DENSE_RANK()를 사용할 수 없기 때문에
-- 이 함수를 활용하지 않는 다른 방법을 찾아야 한다.
-- 예를 들어 급여 순위를 구하고자 한다면
-- 해당 사원의 급여보다 더 큰 값이 몇개인지 확인한 후
-- 확인한 숫자에 『+1』을 추가로 연산해 주면
-- 그 값이 곧 해당 사원의 등수가 된다.
SELECT ENAME, SAL
FROM EMP;
-- 예를 들어.. SMITH보다 급여를 많이 받는 사람은 13명이 있다. 그럼 스미스의 급여 순위는 14!
-- 라는 로직으로 코드 작성
SELECT COUNT(*) +1
FROM EMP
WHERE SAL > 800; -- SMITH의 급여
--==>> 14 -- SMIT의 급여 등수
SELECT COUNT(*) +1
FROM EMP
WHERE SAL > 1600; -- ALLEN의 급여
--==>> 7 -- ALLEN의 급여 등수