본문 바로가기

📚Study Note/ORACLE

[ ORACLE ] RANK() DENSE_RANK()

-- ● 문제 
-- 서브쿼리를 활용하여 TBL_SAWON 테이블을 다음과 같이 조회할 수 있도록 한다.

/*
------------------------------------------------------------------
사원명    성별        현재나이      급여      나이보너스
------------------------------------------------------------------

단, 나이보너스는 현재 나이가 40세 이상이면 급여의 70%
    30세 이상 40 세 미만이면 급여의 50%
    20세 이상 30세 미만이면 급여의 30%
    
또한, 완성된 조회 구문을 기반으로
VIEW_SAWON2 라는 이름의 VIEW 를 생성한다. 
*/
CREATE OR REPLACE VIEW VIEW_SAWON2
AS
SELECT T2.사원명, T2.성별, T2.현재나이, T2.급여
    , CASE WHEN T2.현재나이>=40 THEN T2.급여*0.7
                WHEN T2.현재나이>=30 THEN T2.급여*0.5
                WHEN T2.현재나이>=20 THEN T2.급여*0.3
                ELSE 0
            END "나이보너스"
FROM
(
SELECT *
FROM VIEW_SAWON
)T2;

--==>>View VIEW_SAWON2이(가) 생성되었습니다.

-- VIEW는 순간의 사진을 저장한다는 개념이 아니라
--음,, 서식을 저장해두는 느낌. 사진을 찍어서 저장하는 것이 아니라
--사진을 찍는 '방법'을 저장해두는 느낌이다
--어떻게 표의 데이터를 정리해서 볼 것인지에 대한 방식? 서식은아니고...

            SELECT SANAME "사원명"
                ,  CASE WHEN SUBSTR(JUBUN,7,1) IN ('1','3') THEN '남성'
                        WHEN SUBSTR(JUBUN,7,1) IN ('2','4') THEN '여성'
                        ELSE '성별확인불가'
                    END "성별"
                ,  CASE WHEN SUBSTR(JUBUN,7,1) IN ('1','2')
                        THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1899)
                        WHEN SUBSTR(JUBUN,7,1) IN ('3','4')
                        THEN EXTRACT(YEAR FROM SYSDATE) - (TO_NUMBER(SUBSTR(JUBUN,1,2)) + 1999)
                        ELSE 0
                    END "현재나이"
                , SAL "급여"
            FROM TBL_SAWON;


-- ● 생성된 VIEW 확인
SELECT *
FROM VIEW_SAWON2;
/*
김가영	    여성	28	100	        30
김서현	    여성	28	2000	    600
김아별	    여성	29	5000	    1500
이유림	    여성	26	4000    	1200
정주희	    여성	25	2000	    600
한혜림	    여성	25	2000    	600
이하이	    여성	18	1000    	0
아이유	    여성	21	3000    	900
정준이	    남성	24	4000	    1200
이이제	    여성	20	2000    	600
선동열	    남성	47	3000	    2100
선우선	    여성	23	2000	    600
선우용녀   여성	51	1000	    700
남주혁	    남성	20	2000	    600
남궁선	    남성	17	1000	    0
남이	     남성	 52	2000	    1400        */



-------------------------------------------------------------------------

 

 

 

 

 

-------------------------------------------------------------------------


-- ● RANK() → 등수(순위)를 반환하는 함수
SELECT EMPNO"사원번호", ENAME"사원명", DEPTNO"부서번호", SAL"급여"
FROM EMP;
/*
7369	SMITH	20	800
7499	ALLEN	30	1600
7521	WARD	30	1250
7566	JONES	20	2975
7654	MARTIN	30	1250
7698	BLAKE	30	2850
7782	CLARK	10	2450
7788	SCOTT	20	3000
7839	KING	10	5000
7844	TURNER	30	1500
7876	ADAMS	20	1100
7900    JAMES	30	950
7902    FORD	20	3000
7934	MILLER	10	1300*/




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
778	    CLARK	10	2450	    6
7499	ALLEN	30	1600    	7
7844	TURNER	30	1500    	8
7934	MILLER	10	1300	    9
752	    WARD	30	1250	    10
7654	MARTIN	30	1250	    10
7876	ADAMS	20	1100	    12
790	    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*/




-- ● 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;
/*
7839	KING	10	5000	1	1
7902	FORD	20	3000	1	2
7788	SCOTT	20	3000	1	2
7566	JONES	20	2975	2	3       ※ RANK()의 경우 공동1위 뒤에는 3위가 오며
7698	BLAKE	30	2850	1	4          DENSE_RANK()는 공동 1위 뒤에 2위가 온다.
7782	CLARK	10	2450	2	5
7499	ALLEN	30	1600	2	6
7844	TURNER	30	1500	3	7
7934	MILLER	10	1300	3	8
7521	WARD	30	1250	4	9
7654	MARTIN	30	1250	4	9
7876	ADAMS	20	1100	3	10
7900	JAMES	30	950	    5	11
7369	SMITH	20	800	    4	12
*/

 

 

 

 

 

 

-- ● EMP 테이블의 사원 정보를
-- 사원명, 부서번호, 연봉, 부서내연봉순위, 전체연봉순위 항목으로 조회한다. 

SELECT *
FROM EMP;

SELECT ENAME"사원명", DEPTNO "부서번호", SAL*12+NVL(COMM,0)"연봉"--, 부서내연봉순위, 전체연봉순위
    ,  DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL*12+NVL(COMM,0) DESC) "부서내연봉순위"
    ,  DENSE_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	    2	        3
BLAKE	30	34200	    1	        4
CLARK	10	29400	    2	        5
ALLEN	30	19500	    2	        6
TURNER	30	18000	    3	        7
MARTIN	30	16400	    4	        8
MILLER	10	15600	    3	        9
WARD	30	15500	    5	        10
ADAMS	20	13200	    3	        11
JAMES	30	11400	    6	        12
SMITH	20	9600        4       	13*/
    

SELECT ENAME"사원명", DEPTNO "부서번호", SAL*12+NVL(COMM,0)"연봉"--, 부서내연봉순위, 전체연봉순위
    ,  DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL*12+NVL(COMM,0) DESC)
    ,  DENSE_RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC)
FROM EMP
ORDER BY DEPTNO;


SELECT 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,3 DESC;

/*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
*/



 

 

 

 

 

-- ● EMP 테이블에서 전체 연봉 순위가 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;
--===>> 에러발생  "window  functions are not allowed here"

-- ※ 위의 내용은 RANK() OVER() 함수를  WHERE 조건절에서 사용한 경우이며
-- 이 함수는 WHERE 조건절에서 사용할 수 없기 때문에 발생하는 에러이다.
-- 이 경우, 우리는 INLINE VIEW를 활용하여 풀이해야 한다.
-- 따라서 [첫 번째 방법]은 안됨.


--[두 번째 방법] 

SELECT T.사원명, T.부서번호, T.연봉, 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
*/



-- ● EMP테이블에서 각 부서별 연봉 등수가 1등 부터 2등 까지만 조회한다,
-- 사원번호, 사원명, 부서번호, 연봉, 부서내연봉등수, 전체연봉등수


SELECT *
FROM
(
    SELECT EMPNO "사원번호", 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
)T
WHERE T.부서내연봉순위 IN (1,2);
/*
7839	KING	10	60000	1	1
7902   	FORD	20	36000	1	2
7788	SCOTT	20	36000	1	2
7698	BLAKE	30	34200	1	5
7782	CLARK	10	29400	2	6
7499	ALLEN	30	19500	2	7*/


SELECT T.*
FROM
(
    SELECT EMPNO "사원번호", ENAME"사원명", DEPTNO "부서번호", SAL*12+NVL(COMM,0)"연봉"
        ,  DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL*12+NVL(COMM,0) DESC) "부서내연봉순위"
        ,  DENSE_RANK() OVER(ORDER BY SAL*12+NVL(COMM,0) DESC) "전체연봉순위"
    FROM EMP
)T;
--WHERE T.부서내연봉순위 IN (1,2);
--ORDER BY 3,4 DESC;
/*
7839	KING	10	60000	1	1
7902    FORD	20	36000	1	2
7788	SCOTT	20	36000	1	2
7566	JONES	20	35700	2	3
7698	BLAKE	30	34200	1	4
7782   	CLARK	10	29400	2	5
7499	ALLEN	30	19500	2	6
*/
/*--WHERE T.부서내연봉순위 <=2;  --딱히 데이터의 순서가 의미있는 것은 아니다만
7839	KING	10	60000	1	1
7782   	CLARK	10	29400	2	5
7902   	FORD	20	36000	1	2
7788	SCOTT	20	36000	1	2
7566	JONES	20	35700	2	3
7698	BLAKE	30	34200	1	4
7499	ALLEN	30	19500	2	6*/

--------------------------------------------------------------------------------------