2010. 6. 17.

[ORACLE] 분석용함수의이용 (9i이상)

Contents

1 기본 사항
2 Windowing절에 대한 설명
3 활용 예제

1 기본 사항 #

분석함수는 8i 버전에서 persnal edition, enterprise edition에서 지원하고, 9i버전에서는 모든 버전에 지원된다. 문법은 다음과 같다.

  1. SELECT Analytic_Function ( arguments )
  2. OVER( [ PARTITION BY 칼럼 ] [ ORDER BY] [ Windowing 절] )
  3. FROM 테이블 명;
  4.  
* IE에서 소스 복사시 줄바꿈 안됨. MS-Word 등에 붙여 넣으세요. 줄바꿈 되는 브라우저: Chrome, Opera, Safari

  • Partition By : 전체 집합을 기준에 의해 소그룹으로 나눔
  • Order By : PARTITION BY에 나열된 그룹을 정렬함
  • Windowing : 펑션의 대상이 되는 행 기준으로 범위를 세밀하게 조정 (메뉴얼: window IS a physical or logical SET of rows)

2 Windowing절에 대한 설명 #

RANGE는 값이며, ROWS는 행의 수를 의미한다.
- RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING
  : BETWEEN Current_Row -50 AND 150 의 파티션 내의 모든행이 window
    즉, Current_Row의 값 - 50 ~ Current_Row의 값 + 150의 값은 모두 하나의 그룹

- ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
  : 현재행을 기준으로 파티션 내의 앞/뒤 한건이 Window

- RANGE UNBOUNDED PRECEDING
  : 현재 행을 기준으로 파티션 내의 첫 번째 행까지가 Window

- ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING     
  : 현재행을 기준으로 파티션 내의 첫 번째 행부터 끝 행까지가 Window. 즉, 파티션 모두가 Window

3 활용 예제 #

요것만 이해하면 분석용 함수는 끝난다.
  1.  
  2. SELECT
  3. ename
  4. , sal
  5. , SUM(sal) over(PARTITION BY deptno ORDER BY sal) ASC순으로_부서별_sal누적
  6. , SUM(sal) over(PARTITION BY deptno) 부서별_sal합계
  7. , SUM(sal) over(ORDER BY deptno, sal) deptno_sal_ASC정렬후_누적
  8. , SUM(sal) over() sal총계
  9. FROM emp
  10. ORDER BY deptno, sal;
  11. --over() 안의 oder by는 정렬 후 해당 행과 이전행을 모두 함친 것의 계산 - 여기에서는 SUM()
  12. --over() 안의 partition by는 group by 역할을 한다. 분석에 대한 범위를 지정하는 역할.
  13.  
  14. /*
  15. ENAME SAL ASC순으로_부서별_SAL누적 부서별_SAL합계 DEPTNO_SAL_ASC정렬후_누적 SAL총계
  16. ---------- --------- ------------------------ -------------- ------------------------- ----------
  17. MILLER 1300.00 1300 8750 1300 29025
  18. CLARK 2450.00 3750 8750 3750 29025
  19. KING 5000.00 8750 8750 8750 29025
  20. SMITH 800.00 800 10875 9550 29025
  21. ADAMS 1100.00 1900 10875 10650 29025
  22. JONES 2975.00 4875 10875 13625 29025
  23. SCOTT 3000.00 10875 10875 19625 29025
  24. FORD 3000.00 10875 10875 19625 29025
  25. JAMES 950.00 950 9400 20575 29025
  26. WARD 1250.00 3450 9400 23075 29025
  27. MARTIN 1250.00 3450 9400 23075 29025
  28. TURNER 1500.00 4950 9400 24575 29025
  29. ALLEN 1600.00 6550 9400 26175 29025
  30. BLAKE 2850.00 9400 9400 29025 29025
  31.  
  32. 14 rows selected
  33. */
  34.  
  35.  
  36. --사원 중 직무별로 가장 많은 월급을 받는 사람의 사원번호, 직무명, 월급을 출력하라
  37.  
  38. SELECT T1.EMPNO, T2.JOB, T2.MAX_SAL
  39. FROM EMP T1,
  40. (SELECT JOB, MAX(SAL) AS MAX_SAL
  41. FROM EMP
  42. GROUP BY JOB) T2
  43. WHERE T1.JOB = T2.JOB
  44. AND T1.SAL = T2.MAX_SAL;
  45.  
  46. /*
  47.  
  48. EMPNO JOB MAX_SAL
  49. ----- --------- ----------
  50.  7788 ANALYST 3000
  51.  7902 ANALYST 3000
  52.  7934 CLERK 1300
  53.  7566 MANAGER 2975
  54.  7839 PRESIDENT 5000
  55.  7499 SALESMAN 1600
  56.  
  57. 6 rows selected
  58. */
  59.  
  60. --아래와 같이 분석함수를 사용하면 위와 똑같은 결과를 가져올 수 있다.
  61. --놀라운 것은 테이블을 한번만 읽어서 처리를 할 수 있다는 것이다.
  62. SELECT empno, job, max_job_sal sal
  63. FROM (
  64. SELECT
  65. empno
  66. , job
  67. , sal
  68. , MAX(sal) over (PARTITION BY job) max_job_sal
  69. FROM emp )
  70. WHERE sal = max_job_sal;
  71.  
  72. /*
  73. EMPNO JOB SAL
  74. ----- --------- ----------
  75.  7788 ANALYST 3000
  76.  7902 ANALYST 3000
  77.  7934 CLERK 1300
  78.  7566 MANAGER 2975
  79.  7839 PRESIDENT 5000
  80.  7499 SALESMAN 1600
  81.  
  82. 6 rows selected
  83. */
  84.  
  85. --모든 사원의 월급의 평균에 가장 근접한 사원의 사번과 월급 출력
  86. SELECT empno, sal
  87. FROM (
  88. SELECT
  89. empno
  90. , MIN(abs_sal) over() min_sal
  91. , abs_sal
  92. , sal
  93. FROM (
  94. SELECT
  95. empno
  96. , sal
  97. , ABS(sal - AVG(sal) over()) abs_sal
  98. FROM emp) )
  99. WHERE abs_sal = min_sal;
  100.  
  101. /*
  102. SQL> select avg(sal) from emp;
  103.  
  104.   AVG(SAL)
  105. ----------
  106. 2073.21428
  107.  
  108. EMPNO SAL
  109. ----- ---------
  110.  7782 2450.00
  111. */
  112.  
  113. --부서별로 일련번호를 붙이되 각각의 부서마다 1로 시작하는 일련번호를 붙인다.
  114.  
  115. SELECT
  116. deptno
  117. , empno
  118. , ename
  119. , ROW_NUMBER() over(PARTITION BY deptno ORDER BY deptno)
  120. FROM emp;
  121.  
  122. /*
  123. DEPTNO EMPNO ENAME ROW_NUMBER()OVER(PARTITIONBYDE
  124. ------ ----- ---------- ------------------------------
  125.   10 7782 CLARK 1
  126.   10 7839 KING 2
  127.   10 7934 MILLER 3
  128.   20 7369 SMITH 1
  129.   20 7876 ADAMS 2
  130.   20 7902 FORD 3
  131.   20 7788 SCOTT 4
  132.   20 7566 JONES 5
  133.   30 7499 ALLEN 1
  134.   30 7698 BLAKE 2
  135.   30 7654 MARTIN 3
  136.   30 7900 JAMES 4
  137.   30 7844 TURNER 5
  138.   30 7521 WARD 6
  139.  
  140. 14 rows selected
  141. */
  142.  
  143. --부서별 월급이 많은 순서대로 순위구하기
  144. SELECT
  145. empno
  146. , ename
  147. , sal
  148. , RANK() over(PARTITION BY deptno ORDER BY sal DESC)
  149. FROM emp;
  150.  
  151. /*
  152. --rank() over(PARTITION BY deptno ORDER BY sal DESC)를
  153. --rank() over(PARTITION BY deptno ORDER BY sal ASC)로 고치면 역순이 된다.
  154. --rank()는 동일 순위에 대하여 동일한 값을 리턴하지만 공백이 생긴다.
  155. --즉, 1위에 해당된느 행이 2개이면 2는 존재하지 않고, 바로 3으로 넘어간다.
  156.  
  157. EMPNO ENAME SAL RANK()OVER(PARTITIONBYDEPTNOOR
  158. ----- ---------- --------- ------------------------------
  159.  7839 KING 5000.00 1
  160.  7782 CLARK 2450.00 2
  161.  7934 MILLER 1300.00 3
  162.  7788 SCOTT 3000.00 1
  163.  7902 FORD 3000.00 1
  164.  7566 JONES 2975.00 3
  165.  7876 ADAMS 1100.00 4
  166.  7369 SMITH 800.00 5
  167.  7698 BLAKE 2850.00 1
  168.  7499 ALLEN 1600.00 2
  169.  7844 TURNER 1500.00 3
  170.  7521 WARD 1250.00 4
  171.  7654 MARTIN 1250.00 4
  172.  7900 JAMES 950.00 6
  173. */
  174.  
  175.  
  176.  
  177. SELECT
  178. empno
  179. , ename
  180. , sal
  181. , DENSE_RANK() over(PARTITION BY deptno ORDER BY sal DESC)
  182. FROM emp;
  183.  
  184. /*
  185. dense_rank()는 rank()와는 달리 1위가 2개 존재하면 다음의 순위는 2가 된다.
  186.  
  187. EMPNO ENAME SAL DENSE_RANK()OVER(PARTITIONBYDE
  188. ----- ---------- --------- ------------------------------
  189.  7839 KING 5000.00 1
  190.  7782 CLARK 2450.00 2
  191.  7934 MILLER 1300.00 3
  192.  7788 SCOTT 3000.00 1
  193.  7902 FORD 3000.00 1
  194.  7566 JONES 2975.00 2
  195.  7876 ADAMS 1100.00 3
  196.  7369 SMITH 800.00 4
  197.  7698 BLAKE 2850.00 1
  198.  7499 ALLEN 1600.00 2
  199.  7844 TURNER 1500.00 3
  200.  7521 WARD 1250.00 4
  201.  7654 MARTIN 1250.00 4
  202.  7900 JAMES 950.00 5
  203. */
  204.  
  205. --TOP n개 가져오기
  206. SELECT
  207. empno
  208. , ename
  209. , sal
  210. , RANK
  211. FROM (
  212. SELECT
  213. empno
  214. , ename
  215. , sal
  216. , RANK() over(PARTITION BY deptno ORDER BY sal DESC) RANK
  217. FROM emp)
  218. WHERE RANK <= 3;
  219.  
  220. /*
  221.  
  222. 경우에 따라서 rank(), dense_rank()를 사용한다.
  223.  
  224. EMPNO ENAME SAL RANK
  225. ----- ---------- --------- ----------
  226.  7839 KING 5000.00 1
  227.  7782 CLARK 2450.00 2
  228.  7934 MILLER 1300.00 3
  229.  7788 SCOTT 3000.00 1
  230.  7902 FORD 3000.00 1
  231.  7566 JONES 2975.00 3
  232.  7698 BLAKE 2850.00 1
  233.  7499 ALLEN 1600.00 2
  234.  7844 TURNER 1500.00 3
  235.  
  236. */
  237.  
  238. --피봇
  239. SELECT
  240. deptno
  241. , MAX(CASE WHEN RANK = 1 THEN sal END) rank_1
  242. , MAX(CASE WHEN RANK = 2 THEN sal END) rank_2
  243. , MAX(CASE WHEN RANK = 3 THEN sal END) rank_3
  244. FROM (
  245. SELECT
  246. sal
  247. , deptno
  248. , RANK
  249. FROM (
  250. SELECT
  251. sal
  252. , deptno
  253. , RANK() over(PARTITION BY deptno ORDER BY sal DESC) RANK
  254. FROM emp)
  255. WHERE RANK <= 3 )
  256. GROUP BY deptno
  257.  
  258. /*
  259. DEPTNO RANK_1 RANK_2 RANK_3
  260. ------ ---------- ---------- ----------
  261.   10 5000 2450 1300
  262.   20 3000 2975
  263.   30 2850 1600 1500
  264. */
  265.  
  266. --앞 뒤행 가져오기 lead() lag()
  267. --입사일에 차이에 따른 전/후 월급차이
  268. SELECT
  269. empno
  270. , ename
  271. , sal - LAG(sal, 1) over(ORDER BY hiredate) pre
  272. , sal
  273. , sal - LEAD(sal, 1) over(ORDER BY hiredate) NEXT
  274. FROM emp;
  275.  
  276. /*
  277. EMPNO ENAME PRE SAL NEXT
  278. ----- ---------- ---------- --------- ----------
  279.  7369 SMITH 800.00 -800
  280.  7499 ALLEN 800 1600.00 350
  281.  7521 WARD -350 1250.00 -1725
  282.  7566 JONES 1725 2975.00 125
  283.  7698 BLAKE -125 2850.00 400
  284.  7782 CLARK -400 2450.00 950
  285.  7844 TURNER -950 1500.00 250
  286.  7654 MARTIN -250 1250.00 -3750
  287.  7839 KING 3750 5000.00 4050
  288.  7900 JAMES -4050 950.00 -2050
  289.  7902 FORD 2050 3000.00 1700
  290.  7934 MILLER -1700 1300.00 -1700
  291.  7788 SCOTT 1700 3000.00 1900
  292.  7876 ADAMS -1900 1100.00
  293. */
  294.  
  295. --특정 범위내의 첫행/끝행
  296. SELECT DEPTNO,ENAME,SAL,
  297. FIRST_VALUE(ENAME) OVER(PARTITION BY DEPTNO
  298. ORDER BY SAL DESC
  299. ROWS BETWEEN UNBOUNDED PRECEDING
  300. AND UNBOUNDED FOLLOWING) AS FV,
  301. LAST_VALUE(ENAME) OVER(PARTITION BY DEPTNO
  302. ORDER BY SAL DESC
  303. ROWS BETWEEN UNBOUNDED PRECEDING
  304. AND UNBOUNDED FOLLOWING) AS LV
  305. FROM EMP;
  306.  
  307. /*
  308. DEPTNO ENAME SAL FV LV
  309. ------ ---------- --------- ---------- ----------
  310.   10 KING 5000.00 KING MILLER
  311.   10 CLARK 2450.00 KING MILLER
  312.   10 MILLER 1300.00 KING MILLER
  313.   20 SCOTT 3000.00 SCOTT SMITH
  314.   20 FORD 3000.00 SCOTT SMITH
  315.   20 JONES 2975.00 SCOTT SMITH
  316.   20 ADAMS 1100.00 SCOTT SMITH
  317.   20 SMITH 800.00 SCOTT SMITH
  318.   30 BLAKE 2850.00 BLAKE JAMES
  319.   30 ALLEN 1600.00 BLAKE JAMES
  320.   30 TURNER 1500.00 BLAKE JAMES
  321.   30 WARD 1250.00 BLAKE JAMES
  322.   30 MARTIN 1250.00 BLAKE JAMES
  323.   30 JAMES 950.00 BLAKE JAMES
  324. */
  325.  
  326.  
  327. --RATIO_TO_REPORT : 그룹에서 현재 행의 비율
  328. SELECT JOB, ENAME, SAL,
  329. RATIO_TO_REPORT(SAL) OVER(PARTITION BY JOB) AS RR
  330. FROM EMP
  331. ORDER BY JOB, ENAME;
  332.  
  333. /*
  334. JOB ENAME SAL RR
  335. --------- ---------- --------- ----------
  336. ANALYST FORD 3000.00 0.5
  337. ANALYST SCOTT 3000.00 0.5
  338. CLERK ADAMS 1100.00 0.26506024
  339. CLERK JAMES 950.00 0.22891566
  340. CLERK MILLER 1300.00 0.31325301
  341. CLERK SMITH 800.00 0.19277108
  342. MANAGER BLAKE 2850.00 0.34441087
  343. MANAGER CLARK 2450.00 0.29607250
  344. MANAGER JONES 2975.00 0.35951661
  345. PRESIDENT KING 5000.00 1
  346. SALESMAN ALLEN 1600.00 0.28571428
  347. SALESMAN MARTIN 1250.00 0.22321428
  348. SALESMAN TURNER 1500.00 0.26785714
  349. SALESMAN WARD 1250.00 0.22321428
  350. */
  351.  
  352. --
  353. SELECT ENAME,SAL,
  354. COUNT(*) OVER(ORDER BY SAL
  355. RANGE BETWEEN 149 PRECEDING
  356. AND 0 FOLLOWING) AS m_cnt
  357. FROM EMP;
  358.  
  359. /*
  360. ENAME SAL M_CNT
  361. ---------- --------- ----------
  362. SMITH 800.00 1
  363. JAMES 950.00 2 ---> 950 - 150 ~ 950 + 0, 만약 149로 범위를 줄이면 1로 된다.
  364. ADAMS 1100.00 2
  365. WARD 1250.00 3
  366. MARTIN 1250.00 3
  367. MILLER 1300.00 3
  368. TURNER 1500.00 1
  369. ALLEN 1600.00 2
  370. CLARK 2450.00 1
  371. BLAKE 2850.00 1
  372. JONES 2975.00 2
  373. SCOTT 3000.00 4
  374. FORD 3000.00 4
  375. KING 5000.00 1
  376. */
  377.  
* IE에서 소스 복사시 줄바꿈 안됨. MS-Word 등에 붙여 넣으세요. 줄바꿈 되는 브라우저: Chrome, Opera, Safari

Categories: , , , , , ,

댓글 1개:

Copyright © 화랑천's 소소하기

Distributed By My Blogger Themes | Blogger Theme By NewBloggerThemes 위로