상세 컨텐츠

본문 제목

ORACLE WINDOWING FUNCTION , RATIO_TO_REPORT

관리X 과거글

by 까먹기전에 2015. 1. 23. 14:12

본문

반응형



Windowing 함수 ?

기존에 있던 모든 그룹 Function들에 대해서
Moving & Cumulative Processing을 지원하는 함수이다

SELECT MGR, ENAME, SAL, SUM(SAL) OVER ( PARTITION BY MGR ORDER BY SAL RANGE UNBOUNDED PRECEDING ) AS MGR_SUM
     FROM   EMP ;

 MGR ENAME             SAL    MGR_SUM
---------- ---------- ---------- ----------
      7566 SCOTT            3000       6000 -- 동일 순위의 모든 값에 대한 총합계로 누적됨
      7566 FORD             3000       6000
---------------------------------------------------------------
      7698 JAMES             950        950
      7698 WARD             1250       3450 << 950 + 1250 + 1250 = 3450 
      7698 MARTIN           1250       3450 << 950 + 1250 + 1250 = 3450 
      7698 TURNER           1500       4950 << 950 + 1250 + 1250 + 1500 = 4950 
      7698 ALLEN            1600       6550
---------------------------------------------------------------
      7782 MILLER           1300       1300
---------------------------------------------------------------
      7788 ADAMS            1100       1100
---------------------------------------------------------------
      7839 CLARK            2450       2450
      7839 BLAKE            2850       5300
      7839 JONES            2975       8275
---------------------------------------------------------------
      7902 SMITH             800        800
---------------------------------------------------------------
           KING             5000       5000



* 사원들의 급여와 같은 매니저를 두고 있는 사원들의 SALARY 중 최대값 구함

SQL> SELECT MGR, ENAME, SAL, MAX(SAL) OVER  ( PARTITION BY MGR) AS MGR_MAX
     FROM   EMP ;

       MGR ENAME             SAL    MGR_MAX
---------- ---------- ---------- ----------
      7566 FORD             3000       3000
      7566 SCOTT            3000       3000
---------------------------------------------------------------
      7698 JAMES             950       1600
      7698 ALLEN            1600       1600
      7698 WARD             1250       1600
      7698 TURNER           1500       1600
      7698 MARTIN           1250       1600
---------------------------------------------------------------
      7782 MILLER           1300       1300
---------------------------------------------------------------
      7788 ADAMS            1100       1100
---------------------------------------------------------------
      7839 BLAKE            2850       2975
      7839 JONES            2975       2975
      7839 CLARK            2450       2975
---------------------------------------------------------------
      7902 SMITH             800        800
---------------------------------------------------------------
           KING             5000       5000
---------------------------------------------------------------
14 rows selected.

* 추가로, INLINE VIEW 를 이용해 파티션별로 최대값을 가진 행만 추출

SQL> SELECT MGR, ENAME, SAL
     FROM   ( SELECT MGR, ENAME, SAL, MAX(SAL) OVER ( PARTITION BY MGR ) AS IV_MAX_SAL
              FROM EMP )
     WHERE SAL = IV_MAX_SAL  ;

       MGR ENAME             SAL
---------- ---------- ----------
      7566 FORD             3000 << 최대값 가지는 ROW 가 2건 모두 출력 ,mgr로 묶어서 출력했지만 순위를 매길수없는 동일값은 같이 출력
      7566 SCOTT            3000 << 
      7698 ALLEN            1600
      7782 MILLER           1300
      7788 ADAMS            1100
      7839 JONES            2975
      7902 SMITH             800
           KING             5000


SELECT MGR, ENAME, SAL, MAX(SAL) OVER  ( PARTITION BY MGR order by sal ) AS MGR_MAX
     FROM   EMP ;

order by를 안하면 sort가 안되어서 그룹내 모든애들을 비교해버린다.
order by 하면 현재 row기준으로 검사를 한다


sELECT MGR, ENAME, HIREDATE, SAL,
            ROUND( AVG(SAL) OVER ( PARTITION BY MGR ORDER BY HIREDATE ROWS  BETWEEN unbounded PRECEDING AND unbounded FOLLOWING)) AS MGR_AVG
     FROM EMP ;

BETWEEN unbounded PRECEDING AND unbounded FOLLOWING 기준 행 수치를 안적어주면 그룹내 모든애들을 기준앞뒤를
계산해버린다



SELECT ENAME, SAL,
                COUNT(*) OVER ( ORDER BY SAL RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING ) AS SIM_CNT,
                TO_CHAR(SAL-50)||'->'||TO_CHAR(SAL+150) AS "RANGE" 
         FROM EMP ;

ENAME             SAL    SIM_CNT RANGE
---------- ---------- ---------- ------------------
SMITH             800          2 750->950
JAMES             950          2 900->1100
ADAMS            1100          3 1050->1250 << 1100, 1250, 1250  ==> 3 
WARD             1250          3 1200->1400
MARTIN           1250          3 1200->1400
MILLER           1300          3 1250->1450
TURNER           1500          2 1450->1650
ALLEN            1600          1 1550->1750
CLARK            2450          1 2400->2600
BLAKE            2850          4 2800->3000
JONES            2975          3 2925->3125
SCOTT            3000          3 2950->3150
FORD             3000          3 2950->3150
KING             5000          1 4950->5150



over - 쿼리 result set을 이용해 동작하는 함수
patition by - over( ) 함수 안 partition by을 쓰면 지정값을 분할해주는 역할
order by - partition 내에서 DATA가 어떤 값을 기준으로 정렬될 것인가를 지정(오름,내림차순)
NULLS FIRST | NULLS LAST
NULL이 포함된 ROW가 순서상 제일 앞에 위치할것인지 제일뒤에 위치할 것인지 지정
BETWEEN ... AND -자료의 범위를 결정
UNBOUNDED PRECEDING - 지정된값 이전의 모든 ROW를 포함
UNBOUNDED FOLLOWING - 지정된 값 이후의 모든 ROW를 포함
CURRENT ROW - 현재 ROW를 시작 값 또는 마지막값으로 이용할때 사용함`
INTERVAL - 수행되는 쿼리문을(DATE타입) 전 후를 지정할 수 있다.
EX)RANGE INTERVAL '2' DAY PRECEDING - 2일 전까지의 범위

[따라하기 1-2]
SELECT SALE_DATE , SALE_SITE , SUM(SALE_AMT),
      AVG(SUM(SALE_AMT)) OVER -- 한거를 합계내서 3으로 나눔 (2일전+현재일이니 3으로 나누어야함)
                        (PARTITION BY SALE_SITE --SITE 별로 그룹핑을 함
                          ORDER BY SALE_DATE -- 날짜를 오름차순
                          RANGE INTERVAL '2' DAY PRECEDING ) AS "3일 평균매출액" -- 현재부터 2일전까지 출력
FROM SALE_HIST
GROUP BY SALE_DATE , SALE_SITE;




[따라하기 1-3]
SELECT EMP_ID,SALARY,
      SUM(SALARY) OVER (ORDER BY EMP_iD ROWS 3 PRECEDING) AS "4명급여합계", -- 현재ROW의 앞 3명의 합계
      COUNT(SALARY) OVER (ORDER BY  EMP_ID ROWS 3 PRECEDING) AS "카운트", -- 자기 포함 앞의 카운트
      CEIL(AVG(SALARY) OVER (ORDER BY EMP_ID ROWS 3 PRECEDING)) AS "4명평균" -- 4명의 평균
FROM TEMP;





[따라하기 1-4]
SELECT SALE_DATE , SALE_ITEM , SALE_SITE , SALE_AMT,
        
        FIRST_VALUE(SALE_AMT) OVER -- 마지막 그룹핑한 애들의 첫번째 값을 뽑아옴
                    (PARTITION BY SALE_DATE , SALE_ITEM -- 날짜와 아이템으로 그룹핑한다
                    ORDER BY SALE_AMT-- 그것을 오름차순으로 정렬
                    ROWS BETWEEN UNBOUNDED PRECEDING -- 그룹핑한 애들의 전 후 범위를 지정
                          AND     UNBOUNDED FOLLOWING) AS "첫번째금액",
                          

                                  LAST_VALUE(SALE_AMT) OVER -- 마지막 그룹핑한 애들의 마지막 값을 뽑아옴
                    (PARTITION BY SALE_DATE , SALE_ITEM -- 날짜와 아이템으로 그룹핑한다
                    ORDER BY SALE_AMT -- 그것을 오름차순으로 정렬
                    ROWS BETWEEN UNBOUNDED PRECEDING -- 그룹핑한 애들의 전 후 범위를 지정
                          AND     UNBOUNDED FOLLOWING) AS "마지막금액"
FROM SALE_HIST;







SELECT DEPTNO, ENAME, SAL,
            LAST_VALUE (ENAME) OVER ( PARTITION BY DEPTNO ORDER BY SAL DESC
            ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) AS DEPT_POOR--현재행부터 마지막행까지 검사
FROM EMP ; 

DEPTNO ENAME      SAL                                     DEPT_POOR
------ ---------- --------------------------------------- ----------
10     MILLER     1300.00                                 MILLER
10     CLARK      2450.00                                 MILLER
10     KING       5000.00                                 MILLER
20     SMITH      800.00                                  SMITH
20     ADAMS      1100.00                                 SMITH
20     JONES      2975.00                                 SMITH
20     SCOTT      3000.00                                 SMITH
20     FORD       3000.00                                 SMITH
30     JAMES      950.00                                  JAMES
30     WARD       1250.00                                 JAMES
30     MARTIN     1250.00                                 JAMES
30     TURNER     1500.00                                 JAMES
30     ALLEN      1600.00                                 JAMES
30     BLAKE      2850.00                                 JAMES


RATIO_TO_REPORT 함수
파티션 내 전체 SUM(칼럼) 값에 대한 행별 칼럼 값의 백분율을 소수점으로 구함
0 < 백분율 < 1, 개별 RATIO 의 합 = 1
SQL Server 에서는 지원하지 않는 함수

* JOB 이 SALESMAN 인 사람들을 대상으로 전체 급여에서 본인이 차지하는 비율을 출력 

SQL> SELECT ENAME, SAL, 
            ROUND(RATIO_TO_REPORT(SAL) OVER (),2) AS R_R,
            SUM(SAL) Over ( Order by JOB  ) AS "Total"
     FROM EMP
     WHERE JOB='SALESMAN' ; 

ENAME             SAL        R_R      Total
---------- ---------- ---------- ----------
ALLEN            1600        .29       5600 << ( 1600/5600 )  -- 자신의 sal 이 5600중 얼마나차지하는지 나옴 이 row는 29% 차지
WARD             1250        .22       5600 << ( 1250/5600 ) 
MARTIN           1250        .22       5600 << ( 1250/5600 ) 
TURNER           1500        .27       5600 << ( 1500/5600 ) 


관련글 더보기