계층구조 쿼리란?

오라클 데이터베이스 scott 유저의 emp 테이블을 보면 empno와 mgr컬럼이 있으며, mgr 컬럼 데이터는 해당 사원의 관리자의 empno를 의미 한다.

예를 들어서 아래의 데이터를 보면

1
2
3
4
EMPNO   ENAME    SAL    MGR
------ ------- ------ ------
  7369  SMITH     800   7902
  7902  FORD     3000   7566
  • - empno 7369사원의 관리자는 7902의 empno를 가진 사원이며
  • - empno 7902사원의 관리자는 7566의 empno를 가진 사원이다.

이런 상위 계층과 하위계층의 관계를 오라클에서는 START WITH와 CONNECT BY를 이용해서 쉽게 조회 할 수 있다.

계층구조 쿼리 Synctax

START WITH
  • - 계층 질의의 루트(부모행)로 사용될 행을 지정 한다.
  • - 서브쿼리를 사용할 수도 있다.

CONNECT BY
  • - 이 절을 이용하여 계층 질의에서 상위계층(부모행)과 하위계층(자식행)의 관계를 규정 할 수 있다.
  • PRIOR 연산자와 함께 사용하여 계층구조로 표현할 수 있다.
  • CONNECT BY PRIOR 자식컬럼 = 부모컬럼 : 부모에서 자식으로 트리구성 (Top Down)
  • CONNECT BY PRIOR 부모컬럼 = 자식컬럼 : 자식에서 부모로 트리 구성 (Bottom Up)
  • CONNECT BY NOCYCLE PRIOR : NOCYCLE 파라미터를 이용하여 무한루프 방지
  • - 서브쿼리를 사용할 수 없다.

LEVEL Pseudocolumn
  • - LEVEL은 계층구조 쿼리에서 수행결과의 Depth를 표현하는 의사컬럼이다.

ORDER SIBLINGS BY
  • - ORDER SIBLINGS BY절을 사용하면 계층구조 쿼리에서 편하게 정렬작업을 할 수 있다.

CONNECT BY의 실행순서는 다음과 같다.
  • - 첫째 START WITH 절
  • - 둘째 CONNECT BY 절
  • - 세째 WHERE 절 순서로 풀리게 되어있다.

계층구조 쿼리 예제

간단예제

아래는 직업이 PRESIDENT을 기준으로 계층 구조로 조회하는 예이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- LEVEL컬럼으로 depth를 알수 있다.
-- JONES의 관리자는 KING 이며, SCOTT의 관리자는 JONES 이다.
-- 상/하의 계층 구조를 쉽게 조회 할 수 있다.
SELECT LEVEL, empno, ename, mgr
  FROM emp
 START WITH job = 'PRESIDENT'
CONNECT BY PRIOR  empno = mgr;
 
 
LEVEL      EMPNO  ENAME        MGR
------ -------- --------    -------
     1       7839   KING
     2       7566   JONES      7839
     3       7788   SCOTT      7566
     4       7876   ADAMS      7788
     3       7902   FORD       7566
     4       7369   SMITH      7902
...
PRIOR 연산자 : 상위행의 컬럼임을 나타낸다. CONNECT BY 절에서 상하위간의 관계를 기술할때 사용.

LEVEL의 활용

LEVEL Pseudocolumn을 이용하면 계층구조 쿼리를 좀 더 다양하게 활용 할 수 있다.

아래는 LEVEL의 배율만큼 공백을 왼쪽에 추가하여 계층구조를 한눈에 볼 수 있게 표현한 예이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- SQL*Plus에서만 깔끔하게 보기위해서
COL ename FORMAT A20;
 
 
-- 왼쪽에 LEVEL만큼 공백을 추가하여 계층구조로 조회하는 예제
SELECT LEVEL, LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
  FROM emp
 START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr;
 
 
LEVEL ENAME                     EMPNO    MGR    JOB
------ --------------------    -------  -----  --------
     1 KING                       7839         PRESIDEN
     2     JONES                  7566   7839  MANAGER
     3         SCOTT              7788   7566  ANALYST
     4             ADAMS          7876   7788  CLERK
     3         FORD               7902   7566  ANALYST
     4             SMITH          7369   7902  CLERK
     2     BLAKE                  7698   7839  MANAGER
...

아래는 LEVEL별로 급여 합계와 사원수를 조회하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- LEVEL별로 급여 합계와 사원수를 조회하는 예제
SELECT LEVEL, AVG(sal) total, COUNT(empno) cnt
  FROM emp
 START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr     
 GROUP BY LEVEL
 ORDER BY LEVEL;
 
LEVEL      TOTAL        CNT
-------- ---------- ----------
       1       5000          1
       2       8275          3
       3      13850          8
       4       1900          2

PRIOR의 활용

PRIOR연산자를 SELECT 절에서 사용해보자.

아래는 사원의 관리자를 PRIOR연산자를 이용해서 조회하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- SQL*Plus에서만 깔끔하게 보기위해서
COL mgrname FORMAT A10;
 
 
-- SELECT절에 "PRIOR ename mgrname"을 확인해 보자
SELECT LEVEL, LPAD(' ', 4*(LEVEL-1)) || ename ename,
       PRIOR ename mgrname,
       empno, mgr, job
  FROM emp
 START WITH job='PRESIDENT'
CONNECT BY PRIOR empno=mgr;
 
 
  LEVEL ENAME                MGRNAME         EMPNO        MGR JOB
------- -------------------- ---------- ---------- ---------- ---------
      1 KING                                  7839            PRESIDENT
      2     JONES            KING             7566       7839 MANAGER
      3         SCOTT        JONES            7788       7566 ANALYST
      4             ADAMS    SCOTT            7876       7788 CLERK
      3         FORD         JONES            7902       7566 ANALYST
      2     BLAKE            KING             7698       7839 MANAGER
      3         MARTIN       BLAKE            7654       7698 SALESMAN
      3         TURNER       BLAKE            7844       7698 SALESMAN
      3         JAMES        BLAKE            7900       7698 CLERK
      2     CLARK            KING             7782       7839 MANAGER
      3         MILLER       CLARK            7934       7782 CLERK

PRIOR 연산자 : 상위행의 컬럼임을 나타낸다. CONNECT BY 절에서만 사용할 수 있는 것은 아니다.

분석: 순서대로 보기 바랍니다. 

SELECT LEVEL, LPAD(' ', 4*(LEVEL-1)) || ename ename,
       PRIOR ename mgrname, //3번 이건 아래의 CONNECT BY PRIOR과는 관계없이 사용.
       empno, mgr, job
  FROM emp
 START WITH job='PRESIDENT' //1번 JOB PRESIDENT를 기준으로 레벨을 구성함.
CONNECT BY PRIOR empno=mgr; //2번 자기사전에서 상사사번으로 정렬.

Bottom Up 조회 예제

위 간단 예제를 역순(자식에서 부모로 트리 구성, Bottom Up)으로 조회 해 보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- SQL*Plus에서만 깔끔하게 보기위해서
COL ename FORMAT A20;
 
 
-- ename을 기준으로 Bottom Up으로 조회하는 예제이다.
SELECT LEVEL, LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
  FROM emp
 START WITH ename='SMITH'  -- 최 하위 노드 값이 와야 한다.
CONNECT BY PRIOR mgr = empno;
 
 
LEVEL ENAME                EMPNO      MGR    JOB
------ ---------------    -------- -------- ---------
     1 SMITH                 7369     7902   CLERK
     2     FORD              7902     7566   ANALYST
     3         JONES         7566     7839   MANAGER
     4             KING      7839            PRESIDENT

PRIOR 컬럼에 따라(상위 OR 하위) 계층전개 방향이 달라진다.
  • - 순방향(Top Down-상위~하위) : PRIOR 하위 = 상위
  • - 역방향(Bottom Up-하위~상위) : PRIOR 상위 = 하위

분석:순서대로 보자.

-- ename을 기준으로 Bottom Up으로 조회하는 예제이다.
SELECT LEVEL, LPAD(' ', 4*(LEVEL-1)) || ename ename, empno, mgr, job
  FROM emp
 START WITH ename='SMITH'  --//1번 최 하위 노드 값이 기준이 된다.
CONNECT BY PRIOR mgr = empno; //2번 사번에서 상사사번으로 레벨정렬 말이좀 애매하다. 여하튼

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/1300
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

계층구조 쿼리의 활용2  (0) 2014.12.03
계층구조 쿼리의 활용  (0) 2014.12.03
GROUPING SETS  (0) 2014.12.03
CUBE GROUP BY CUBE  (0) 2014.12.03
GROUPING과 GROUPING_ID  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

GROUPING SETS

Oracle 2014. 12. 3. 16:38

GROUPING SETS

  • - GROUPING SETS 함수는 GROUP BY의 확장된 형태로 하나의 GROUP BY절에 여러개의 그룹 조건을 기술할 수 있다.
  • - GROUPING SETS 함수의 결과는 각 그룹 조건에 대해 별도로 GROUP BY한 결과를 UNION ALL한 결과와 동일하다.
  • - GROUPING SETS 함수를 사용하면 UNION ALL등을 사용하여 복잡하게 SQL문장을 작성했던 것을 간단하게 한 문장으로 해결 할 수 있다.

아래는 GROUPING SETS함수와 GROUP BY, UNION ALL을 이용하여 동일한 결과를 출력하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
--  GROUPING SETS 예제
SELECT deptno, job, SUM(sal)
 FROM emp
 GROUP BY GROUPING SETS(deptno, job);
 
 
-- GROUP BY와 UNION ALL을 이용한 예제
SELECT NULL deptno,  job, SUM(sal)
  FROM emp
 GROUP BY job
 UNION ALL
SELECT deptno, NULL job, SUM(sal)
  FROM emp
 GROUP BY deptno;
 
 
-- 조회결과
   DEPTNO JOB                  SUM(SAL)
--------- ------------------ ----------
          CLERK                    4150
          SALESMAN                 5600
          PRESIDENT                5000
          MANAGER                  8275
          ANALYST                  6000
       30                          9400
       20                         10875
       10                          8750

분석:순서대로 보기 바란다. 

--  GROUPING SETS 예제
SELECT deptno, job, SUM(sal)
 FROM emp
 GROUP BY GROUPING SETS(deptno, job); //1번 이것도 오른쪽우선으로 그룹이묶인결과가 출력이 된다. JOB 그룹별 월급의합 결과 그담 부서별 그룹의 월급의 합

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2680
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

계층구조 쿼리의 활용  (0) 2014.12.03
오라클 계층구조 쿼리  (0) 2014.12.03
CUBE GROUP BY CUBE  (0) 2014.12.03
GROUPING과 GROUPING_ID  (0) 2014.12.03
Rollup  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

CUBE GROUP BY CUBE

Oracle 2014. 12. 3. 16:28

CUBE operator

CUBE 강좌를 보기 전에 바로 전에 있는 ROLLUP 강좌를 꼭 보기 바란다.

ROLLUP 예제
 
SQL> SELECT b.dname, a.job, SUM(a.sal) sal, 
            COUNT(a.empno) emp_count
     FROM emp a, dept b
     WHERE a.deptno = b.deptno
     GROUP BY ROLLUP(b.dname, a.job);


DNAME      JOB               SAL  EMP_COUNT
---------- ---------- ---------- ----------
ACCOUNTING CLERK            1300          1
ACCOUNTING MANAGER          2450          1
ACCOUNTING PRESIDENT        5000          1
ACCOUNTING                  8750          3  -->  ACCOUNTING 부서의 급여 합계와 전체 사원 수
RESEARCH   ANALYST          6000          2
RESEARCH   CLERK            1900          2
RESEARCH   MANAGER          2975          1
RESEARCH                   10875          5 -->  RESEARCH 부서의 급여 합계와 전체 사원 수
SALES      MANAGER         28500          1
SALES      SALESMAN         4000          3
SALES                      32500          4 -->  SALES부서의 급여 합계와 전체 사원 수
                               52125         12 ->  전체 급여 합계와 전체 사원 수
    

위의 SQL의 결과를 보면 부서별로 각 직업에 해당하는 급여와 사원수를 볼 수 있다.

하지만 부서별로 각 직업의 급여와 사원수, 그리고 또 각 직업별로 급여 합계와 사원수를 보기 위해서는 두개의ROLLUP을 사용해서 SQL문을 작성해야 한다.

 
-- 이렇게 하면 되겠죠..
SQL> SELECT b.dname, a.job, SUM(a.sal) sal, COUNT(a.empno) emp_count
     FROM emp a, dept b
     WHERE a.deptno = b.deptno
     GROUP BY ROLLUP(b.dname, a.job)
     UNION
     SELECT ' ', job, SUM(sal) sal, COUNT(empno) emp_count
     FROM emp
     GROUP BY ROLLUP(job);
 
DNAME      JOB               SAL  EMP_COUNT
---------- ---------- ---------- ----------
ACCOUNTING  CLERK           1300          1
ACCOUNTING  MANAGER         2450          1
ACCOUNTING  PRESIDENT       5000          1
ACCOUNTING                  8750          3
RESEARCH    ANALYST         6000          2
RESEARCH    CLERK           1900          2
RESEARCH    MANAGER         2975          1
RESEARCH                   10875          5
SALES       MANAGER        28500          1
SALES       SALESMAN        4000          3
SALES                      32500          4  --> 요기 까지는 첫 번째 ROLLUP을 이용
             ANALYST         6000           2
            CLERK           3200          3
            MANAGER        33925          3
            PRESIDENT       5000          1
            SALESMAN        4000          3
                           52125         12  --> 요 부분은 두 번째 ROLLUP을 이용
    

CUBE를 사용하면 편하게 하나의 SQL문으로 위의 결과를 얻을 수 있다. 직접 아래 SQL문을 실행시켜 보면 쉽게 이해가 간다.

 
SQL> SELECT b.dname, a.job, SUM(a.sal) sal, COUNT(a.empno) emp_count
     FROM emp a, dept b
     WHERE a.deptno = b.deptno
     GROUP BY CUBE(b.dname, a.job)

DNAME      JOB               SAL  EMP_COUNT
---------- ---------- ---------- ----------
ACCOUNTING  CLERK            1300          1
ACCOUNTING  MANAGER          2450          1
ACCOUNTING  PRESIDENT        5000          1
ACCOUNTING                   8750          3 --> ACCOUNTING 부서의 직업별 급여의 총계와 사원 수.
RESEARCH    ANALYST          6000          2
RESEARCH    CLERK            1900          2
RESEARCH    MANAGER          2975          1
RESEARCH                    10875          5 --> RESEARCH 부서의 직업별 급여의 총계와 사원 수.
SALES       MANAGER         28500          1
SALES       SALESMAN         4000          3
SALES                       32500          4 --> SALES 부서의 직업별 급여 총계와 사원 수.
            ANALYST          6000          2
            CLERK            3200          3
            MANAGER         33925          3
            PRESIDENT        5000          1
            SALESMAN         4000          3   
                            52125         12  --> 직업별로 급여의  총계와 사원 수.

-- CUBE를 어느 경우에 사용 할 수 있는지 이해 되셨죠..
-- CUBE는 Cross-Tab에 대한 Summary를 추출하는데 사용 된다
-- 즉 ROLLUP에 의해 나타 내어지는 Item Total값과 Column Total값을 나타 낼 수 있다.    
    

분석: 결과값 아래에 추가문구가 있지만 CUBE를 이해하기에 부족해서 좀더 검색해보았다.
- GROUP BY절에 있는 모든 컬럼들에 대한 가능한 모든 조합을 그룹으로 생성한다. 이렇다단다.
- 순번대로 보시길.

SELECT b.dname, a.job, SUM(a.sal) sal, COUNT(a.empno) emp_count FROM emp a, dept b WHERE a.deptno = b.deptno GROUP BY CUBE(b.dname, a.job) // 1번 CUBE로 조합을 생성해낸다 ROLLUP함수를 섰을때 조합되어지는 결과값이 먼저 출력되는걸 볼수 있고 그다음 A.JOB에대한 조합으로 결과값도 추가로 볼수 있음을 알수 있다.



태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/1846
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

오라클 계층구조 쿼리  (0) 2014.12.03
GROUPING SETS  (0) 2014.12.03
GROUPING과 GROUPING_ID  (0) 2014.12.03
Rollup  (0) 2014.12.03
KEEP  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

GROUPING과 GROUPING_ID

Oracle 2014. 12. 3. 15:47

GROUPING과 GROUPING_ID

GROUPING (컬럼)
  • - GROUPING 함수는 ROLLUP, CUBE에 모두 사용할 수 있다.
  • - GROUPING 함수는 해당 컬럼의 Row가 GROUP BY에 의해서 산출된 Row인 경우에는 0을 반환하고, ROLLUP이나 CUBE에 의해서 산출된 Row인 경우에는 1을 반환하게 된다.
  • - 따라서 해당 Row가 결과집합에 의해 산출된 Data 인지, ROLLUP이나 CUBE에 의해서 산출된 Data 인지를 알 수 있도록 지원하는 함수이다.

GROUPING_ID(컬럼a, 컬럼b[, …])
  • - GROUPING(컬럼a)||GROUPING(컬럼b)의 값을 2진수에서 10진수로 변환한 값이다.

아래는 GROUPING과 GROUPING_ID의 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
SELECT deptno
     , empno
     , SUM(sal) s_sal
     , GROUPING(deptno) grp_dept
     , GROUPING(empno)  grp_emp
     , GROUPING_ID(deptno, empno) gid
  FROM emp
 GROUP BY ROLLUP(deptno, empno)
;
 
 
-- GRP_DEPT : deptno로 GROUP BY 되면 0, deptno의 값이 없으면 1
-- GRP_EMP : empno로 GROUP BY 되면 0, empno의 값이 없으면 1
-- GID : GROUPING(deptno) || GROUPING(empno)의 값을 2진수에서 10진수로 변환한 값
DEPTNO      EMPNO      S_SAL   GRP_DEPT    GRP_EMP        GID
------ ---------- ---------- ---------- ---------- ----------
    10       7782       2450          0          0          0
    10       7839       5000          0          0          0
    10       7934       1300          0          0          0
    10                  8750          0          1          1
    20       7369        800          0          0          0
    20       7566       2975          0          0          0
    20       7788       3000          0          0          0
    20       7876       1100          0          0          0
    20       7902       3000          0          0          0
    20                 10875          0          1          1
    30       7900        950          0          0          0
    30       7499       1600          0          0          0
    30       7521       1250          0          0          0
    30       7654       1250          0          0          0
    30       7698       2850          0          0          0
    30       7844       1500          0          0          0
    30                  9400          0          1          1
                       29025          1          1          3

분석:순번대로 보기 바람

SELECT deptno
     , empno
     , SUM(sal) s_sal
     , GROUPING(deptno) grp_dept //2번 deptno로 group by되면 0,deptno의 값이 없으면 1
     , GROUPING(empno)  grp_emp //3번 empno로 group by되면 0,empno의 값이 없으면 1
     , GROUPING_ID(deptno, empno) gid //4번 GROUPING(deptno) || GROUPING(empno)의 값을 2진수에서 10진수로 변환한 값 이라는데 1 1 이니까 11이되나봄 11의 10진수 값은 3 음..
  FROM emp
 GROUP BY ROLLUP(deptno, empno) //1번 2개의 조건으로 그룹을 엮음
;

소계만 표시, 총계 제거

아래는 부서별 소계만 조회하고, 전체 총계는 조회하지 않는 예제이다. 위 GROUPING과 GROUPING_ID 예제 실행결과 [GROUPING(deptno)=0] 조건으로 소계만 조회가 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SELECT deptno
     , DECODE(GROUPING(empno),1,'소계',empno) empno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP(deptno, empno)
HAVING GROUPING(deptno) = 0
;
 
 DEPTNO EMPN      S_SAL
------- ---- ----------
     10 7782       2450
     10 7839       5000
     10 7934       1300
     10 소계       8750
     20 7369        800
     20 7566       2975
     20 7788       3000
     20 7876       1100
     20 7902       3000
     20 소계      10875
     30 7900        950
     30 7499       1600
     30 7521       1250
     30 7654       1250
     30 7698       2850
     30 7844       1500
     30 소계       9400

분석: 순번대로 보기 바람

SELECT deptno
     , DECODE(GROUPING(empno),1,'소계',empno) empno //3번 empno의 GROUPING값이 1일때만 소계 아니면 empno값을 그대로 추력해주는 문
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP(deptno, empno) //1번 deptno와 empno로 그룹
HAVING GROUPING(deptno) = 0 // 2번 그룹핑값이 deptno가 0일때만
;

아래와 같이 GROUP BY 절에서 empno만 ROLLUP 연산[GROUP BY deptno, ROLLUP(empno)]을 하여도 동일한 결과를 얻을 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SELECT deptno
     , DECODE(GROUPING(empno),1,'소계',empno) empno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY deptno, ROLLUP(empno)
;
 
 
 DEPTNO EMPN      S_SAL
------- ---- ----------
     10 7782       2450
     10 7839       5000
     10 7934       1300
     10 소계       8750
     20 7369        800
     20 7566       2975
     20 7788       3000
     20 7876       1100
     20 7902       3000
     20 소계      10875
     30 7900        950
     30 7499       1600
     30 7521       1250
     30 7654       1250
     30 7698       2850
     30 7844       1500
     30 소계       9400

분석:순번대로 보기 바람.

SELECT deptno
     , DECODE(GROUPING(empno),1,'소계',empno) empno //2번 empno의 GROUPING값이 1일때만 소계 아니면 empno값을 그대로 추력해주는 문
     , SUM(sal) s_sal
  FROM emp
 GROUP BY deptno, ROLLUP(empno) //1번 그룹을 이렇게 엮으면 deptno가 중심이 되지만 deptno에대한 총합은 구해지지 않는다 empno만 그룹으로 묶어 합을 구하게된다.

총계만 표시, 소계 제거

아래는 전체 총계만 조회하고, 소계는 조회하지 않는 예제이다. 위 GROUPING과 GROUPING_ID 예제 실행결과 [GROUPING_ID(deptno, empno) != 1] 조건으로 소계만 조회가 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT deptno
     , DECODE(GROUPING(deptno),1,'합계',empno) empno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP(deptno, empno)
HAVING GROUPING_ID(deptno, empno) != 1
;
 
 DEPTNO EMPN      S_SAL
------- ---- ----------
     10 7782       2450
     10 7839       5000
     10 7934       1300
     20 7369        800
     20 7566       2975
     20 7788       3000
     20 7876       1100
     20 7902       3000
     30 7900        950
     30 7499       1600
     30 7521       1250
     30 7654       1250
     30 7698       2850
     30 7844       1500
        합계      29025
분석:위에분석이 되어서 그런가 쉽게 되는듯 하다 순번대로 보시기 바란다.
SELECT deptno
     , DECODE(GROUPING(deptno),1,'합계',empno) empno ////3번 deptnoGROUPING값이 1일때만 '합계' 아니면 empno값을 그대로 추력해주는 문
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP(deptno, empno) //1번 둘다 묶었다. 전체 월급합과 부서별 월급합이 나옴을 알수 있다.
HAVING GROUPING_ID(deptno, empno) != 1 //2번 그런데 두 조건의 || 연산으로 나온 값의 십진수값이 1이 아닐때만 출력하란다. 그럼 둘다 0 0 일때와 1 1 일때만 출력될것이다. || 연산이 |연산이 아니라 문자로 합치기이다 그래서 1,0이면 10 ㅎ 0,1이면 1 이다. 10이 이진수이므로 십진수로 교체하면 2가된다. 그런데 1,0의 경우의수는 없는듯하다.
;

아래와 같이 ROLLUP 연산을 괄호로 묶어[GROUP BY ROLLUP((deptno, empno))]서 처리가 가능하다. 괄호로 묶은 항목은 하나의 항목처럼 묶여 처리 된다. 이는 코드와 명칭을 함께 그룹바이 롤업할때 주로 사용된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT deptno
     , DECODE(GROUPING(deptno),1,'합계',empno) empno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP((deptno, empno))
;
 
 
 DEPTNO EMPN      S_SAL
------- ---- ----------
     10 7782       2450
     10 7839       5000
     10 7934       1300
     20 7369        800
     20 7566       2975
     20 7788       3000
     20 7876       1100
     20 7902       3000
     30 7900        950
     30 7499       1600
     30 7521       1250
     30 7654       1250
     30 7698       2850
     30 7844       1500
        합계      29025

분석:순번대로 보기 바란다.

SELECT deptno
     , DECODE(GROUPING(deptno),1,'합계',empno) empno //3번 deptnoGROUPING값이 1일때만 '합계' 아니면 empno값을 그대로 추력해주는 문
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP((deptno, empno)) //1번 그룹으로 묶는데 가로를 하나 더 쳤다.. 앞서봤던예제와 결과가 같은데 이런방식도 있음을 알아두자 그런데 이건 좀 아닌듯.
;

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2679
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

GROUPING SETS  (0) 2014.12.03
CUBE GROUP BY CUBE  (0) 2014.12.03
Rollup  (0) 2014.12.03
KEEP  (0) 2014.12.03
LAG, LEAD (다른 행의 값을 참조)  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

Rollup

Oracle 2014. 12. 3. 14:29

Rollup과 Cube는?

  • - GROUP BY 구문의 결과에 소계 및 합계 정보를 추가로 나타내 주는 함수
  • - 복잡한 과정 없이 간단한 구문만으로 소계 정보를 쉽게 구할 수 있다.
  • Rollup : 단계별 소계
  • Cube : 모든 경우의 수에 대한 소계

Rollup 기본예제

Rollup 예제 1

아래는 부서별 급여합계와 전체 합계를 조회하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT deptno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP(deptno)
;
 
-- ROLLUP 연산으로 29025 출력
 DEPTNO      S_SAL
------- ----------
     10       8750
     20      10875
     30       9400
             29025

분석: 순서대로 보기 바람.

SELECT deptno
     , SUM(sal) s_sal //1번 월급의 평균
  FROM emp
 GROUP BY ROLLUP(deptno); //deptno 전체를 구룹으로 묶어서 deptno와 s_sal을 한번더 출력해줌.

아래는 UNION ALL을 이용하여 위 ROLLUP 예제와 동일한 결과를 조회하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SELECT deptno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY deptno
 UNION ALL
SELECT NULL deptno
     , SUM(sal) s_sal
  FROM emp
;
 
 
 
 DEPTNO      S_SAL
------- ----------
     30       9400
     20      10875
     10       8750
             29025

Rollup 예제 2

아래는 부서별 사원의 급여와 소계, 그리고 전체 합계(총계)를 조회하는 예제이다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SELECT deptno
     , empno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP (deptno, empno)
;
 
 
 DEPTNO      EMPNO      S_SAL
------- ---------- ----------
     10       7782       2450
     10       7839       5000
     10       7934       1300
     10                  8750
     20       7369        800
     20       7566       2975
     20       7788       3000
     20       7876       1100
     20       7902       3000
     20                 10875
     30       7900        950
     30       7499       1600
     30       7521       1250
     30       7654       1250
     30       7698       2850
     30       7844       1500
     30                  9400
                        29025
GROUP BY ROLLUP (DEPTNO, EMPNO) : 롤업의 항목을 오른쪽부터 하나씩 차례로 없애가며 그룹바이한 결과의 합집합

분석:순서대로 보기 바람.

SELECT deptno
     , empno
     , SUM(sal) s_sal
  FROM emp
 GROUP BY ROLLUP (deptno, empno) //1번 그룹을 하는데 deptno와 empno를 기준으로 함 결과는 s_sal로써. deptno를 기준으로 empno의 합을 구해서 출력해주고그담 deptno를 기준으로 전체의 합을 구해줌 ~
;

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2678
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.

--------------------------추가 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

ROLLUP operator

ROLLUP구문은 GROUP BY 절과 같이 사용 되며, GROUP BY절에 의해서 그룹 지어진 집합 결과에 대해서 좀 더 상세한 정보를 반환하는 기능을 수행 한다.

SELECT절에 ROLLUP을 사용함으로써 보통의 SELECT된 데이터와 그 데이터의 총계를 구할 수 있다.

간단 예제
 
-- 먼저 GROUP BY를 사용해서 직업별로 급여 합계를 구하는 예제이다.
SQL> SELECT job, SUM(sal)
     FROM emp
     GROUP BY job; 

JOB          SUM(SAL)
---------- ----------
ANALYST         600
CLERK          3200
MANAGER       33925
PRESIDENT      5000
SALESMAN       4000


-- ROLLUP을 사용해서 직업별로 급여 합계와  총계를 구하는 예제이다.
SQL> SELECT job, SUM(sal)
     FROM emp
     GROUP BY ROLLUP(job);
 

JOB          SUM(SAL
---------- ----------
ANALYST         6000
CLERK           3200
MANAGER        33925
PRESIDENT       5000
SALESMAN        4000
               52125   --> 급여 합계에 대한 총계가 추가 되었다.
    

좀 더 복잡한 예제

부서별로 인원수와 급여 합계를 구하는 예제

 
-- GROUP BY절을 사용 한 결과
SQL> SELECT b.dname, a.job, SUM(a.sal) sal, 
            COUNT(a.empno) emp_count
     FROM emp a, dept b
     WHERE a.deptno = b.deptno
     GROUP BY b.dname, a.job

DNAME       JOB               SAL  EMP_COUNT
----------  ---------- ---------- ----------
ACCOUNTING  CLERK            1300          1
ACCOUNTING  MANAGER          2450          1
ACCOUNTING  PRESIDENT        5000          1
RESEARCH    ANALYST          6000          2
RESEARCH    CLERK            1900          2
RESEARCH    MANAGER          2975          1
SALES       MANAGER         28500          1
SALES       SALESMAN         4000          3


-- 부서별로 인원과, 급여합계가 한 눈에 보이지 않는다.
-- 일일이 부서에 해당하는 직업별 급여와 사원수를 일일이 더해야 한다.

-- 이런 경우 ROLLUP을 사용하여 쉽게 조회 할 수 있다. 
SQL> SELECT b.dname, a.job, SUM(a.sal) sal, 
            COUNT(a.empno) emp_count
     FROM emp a, dept b
     WHERE a.deptno = b.deptno
     GROUP BY ROLLUP(b.dname, a.job)


DNAME      JOB               SAL  EMP_COUNT
---------- ---------- ---------- ----------
ACCOUNTING CLERK            1300          1
ACCOUNTING MANAGER          2450          1
ACCOUNTING PRESIDENT        5000          1
ACCOUNTING                  8750          3  -->  ACCOUNTING 부서의 급여 합계와 전체 사원 수
RESEARCH   ANALYST          6000          2
RESEARCH   CLERK            1900          2
RESEARCH   MANAGER          2975          1
RESEARCH                   10875          5 -->  RESEARCH 부서의 급여 합계와 전체 사원 수
SALES      MANAGER         28500          1
SALES      SALESMAN         4000          3
SALES                      32500          4 -->  SALES부서의 급여 합계와 전체 사원 수
                               52125         12 ->  전체 급여 합계와 전체 사원 수
 

-- 위와 같이ROLLUP은 일반적인 누적에 대한 총계를 구할 때 아주 편리하게 사용 할 수 있다.
    
분석:순서대로 보자
SELECT b.dname, a.job, SUM(a.sal) sal, 
            COUNT(a.empno) emp_count
     FROM emp a, dept b

WHERE a.deptno = b.deptno //1번 부서끼리 조인시키고. GROUP BY ROLLUP(b.dname, a.job) //부서명과 직책별로 그룹후 rollup시키고 결과를 출력하는데 부서를 출력후 잡별로 인원카운팅을 하고 하합계도 구하고 부서의 잡의 총 급여와 인원수를 구해주고 최종적으로 전체 합계를 다시 결과로 알려줌.







태그

ROLLUP


문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/1845
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

CUBE GROUP BY CUBE  (0) 2014.12.03
GROUPING과 GROUPING_ID  (0) 2014.12.03
KEEP  (0) 2014.12.03
LAG, LEAD (다른 행의 값을 참조)  (0) 2014.12.03
윈도우 함수 WINDOWNING PRECEDING  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

KEEP

Oracle 2014. 12. 3. 14:11

KEEP (최초값, 최종값)

KEEP 함수의 사용방법은 아래와 같으며, 예제를 실습하면서 이해해 보겠습니다.

  • MAX() KEEP(DENSE_RANK FIRST[LAST] ORDER BY)
  • MIN() KEEP(DENSE_RANK FIRST[LAST] ORDER BY)

아래는 부서별 최대급여자 급여(MAX_SAL)와 사번(MAX_E), 최소급여자 급여(MIN_SAL)와 사번(MIN_E)을 조회하는 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT deptno
     , MAX(sal) max_sal
     , MAX(empno) KEEP(DENSE_RANK LAST  ORDER BY sal) max_e
     , MIN(sal) min_sal
     , MIN(empno) KEEP(DENSE_RANK FIRST ORDER BY sal) min_e
  FROM emp
 GROUP BY deptno
 ORDER BY deptno
;
 
 DEPTNO    MAX_SAL      MAX_E    MIN_SAL      MIN_E
------- ---------- ---------- ---------- ----------
     10       5000       7839       1300       7934
     20       3000       7902        800       7369
     30       2850       7698        950       7900

KEEP은 분석함수인가? 아니다. KEEP은 집계함수이다.
  • 1. 그룹별 집계결과를 1개행으로 반환
  • 2. OVER 구문이 없다.

분석: 순서대로 보기 바람 위에 keep(최초값, 최종값)은 무시하고 보기바람.

SELECT deptno
     , MAX(sal) max_sal //1번:월급의 최고값
     , MAX(empno) KEEP(DENSE_RANK LAST  ORDER BY sal) max_e //2번 max로 최대값임 근데 사번을 기준으로 구하는게 아니라 keep함수로인해 dense_rank로 sal에대한 순위값중 마지막값을 기준으로 사번을 선택
     , MIN(sal) min_sal //3번 최저월급
     , MIN(empno) KEEP(DENSE_RANK FIRST ORDER BY sal) min_e //4번 역시 사원번호를 가져오는데 sal의 순위중 최초값을 기준으로 사번을 가져옴.
  FROM emp
 GROUP BY deptno
 ORDER BY deptno

KEEP을 사용하지 않을경우 아래와 같은 SQL문으로 동일한 결과를 얻을 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT a.deptno
     , a.max_s
     , e1.empno max_e
     , a.min_s
     , e2.empno min_e
  FROM (SELECT deptno
             , MAX(sal) max_s
             , MIN(sal) min_s
          FROM emp
         GROUP BY deptno
        ) a
     , emp e1
     , emp e2
 WHERE a.deptno = e1.deptno
   AND a.max_s  = e1.sal
   AND a.deptno = e2.deptno
   AND a.min_s  = e2.sal
 ORDER BY a.deptno
;

분석:분석눈으로만 해보세요.

LISTAGG (문자열합치기)

  • - 함수 이름 그대로 LIST를 구분자로 AGGREGATE 해주는 함수이며, 행 데이터를 특정 구분자를 가지는 열로 쉽게 표현할 수 있다.
  • - Oracle11g R2 버전부터 사용 할 수 있다.
  • - LISTAGG(컬럼, 구분값) WITHIN GROUP( ORDER BY 절) 형식으로 사용한다.

아래는 버전별 정리로 문자열 합치는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT deptno
     , SUBSTR(XMLAgg(XMLELEMENT(x, ',', empno) ORDER BY empno).Extract('//text()'), 2) "9i"
     , WM_CONCAT(empno) "10g"
     , LISTAGG(empno, ',') WITHIN GROUP(ORDER BY empno) "11g"
  FROM emp
 GROUP BY deptno
 ORDER BY deptno
 
 
 DEPTNO 9i                            10g                           11g                          
------- ----------------------------- ----------------------------- -------------------------------
     10 7782,7839,7934                7782,7934,7839                7782,7839,7934               
     20 7369,7566,7788,7876,7902      7369,7876,7788,7902,7566      7369,7566,7788,7876,7902     
     30 7499,7521,7654,7698,7844,7900 7499,7900,7844,7698,7654,7521 7499,7521,7654,7698,7844,7900

WM_CONCAT은 정렬을 사용 할 수 없으며, 그 외 방법들은 정렬 기능을 사용 한 것을 확인 할 수 있다.

LISTAGG 는 집계함수이다. WM_CONCAT 에서는 정렬이 안된다.

분석: 각버전별로 분자열합치는 내용임 11g에서 추가된것이 정렬이 가능해졌고 구분자도 입력할수 있음. 

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2676
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

GROUPING과 GROUPING_ID  (0) 2014.12.03
Rollup  (0) 2014.12.03
LAG, LEAD (다른 행의 값을 참조)  (0) 2014.12.03
윈도우 함수 WINDOWNING PRECEDING  (0) 2014.12.03
집계함수 -> 분석함수 사용하기  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

LAG, LEAD (다른 행의 값을 참조)

  • LAG (컬럼명[,offset][,default]) : 현재 ROW 기준으로 이전 행을 참조
  • LEAD (컬럼명[,offset][,default]) : 현재 ROW 기준으로 다음 행을 참조

아래 예제는 이전 row(S_1), 다음 row(S_2), 다음 두 번째 row(S_3)의 급여를 조회하는 예제이다. 다음 두 번째 row(S_3) 값이 NULL인 경우 0을 출력한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SELECT deptno, empno, sal
     , LAG (sal) OVER(ORDER BY deptno, empno) s_1
     , LEAD(sal) OVER(ORDER BY deptno, empno) s_2
     , LEAD(sal, 2, 0) OVER(ORDER BY deptno, empno) s_3
  FROM emp
;
 
 
-- S_1 : 이전 ROW 의 급여 값을 출력한다.
-- S_2 : 다음 ROW 의 급여 값을 출력한다.
-- S_3 : 다음 두 번째 ROW의 급여 값을 출력한다. 만약 값이 없으면 0을 출력한다.
  DEPTNO      EMPNO        SAL        S_1        S_2        S_3
-------- ---------- ---------- ---------- ---------- ----------
      10       7782       2450                  5000       1300
      10       7839       5000       2450       1300        800
      10       7934       1300       5000        800       2975
      20       7369        800       1300       2975       3000
      20       7566       2975        800       3000       1100
      20       7788       3000       2975       1100       3000
      20       7876       1100       3000       3000       1600
      20       7902       3000       1100       1600       1250
      30       7499       1600       3000       1250       1250
      30       7521       1250       1600       1250       2850
      30       7654       1250       1250       2850       1500
      30       7698       2850       1250       1500        950
      30       7844       1500       2850        950          0
      30       7900        950       1500                     0

LAG, LEAD 함수 사용시 ORDER BY 절은 필수 입력사항 이다.

분석: 순서대로 보기 바람

SELECT deptno, empno, sal
     , LAG (sal) OVER(ORDER BY deptno, empno) s_1 //1번 함수 고유의 기능대충이제 알겠다.
     , LEAD(sal) OVER(ORDER BY deptno, empno) s_2 //2번 다음 로우값을 출력.
     , LEAD(sal, 2, 0) OVER(ORDER BY deptno, empno) s_3 //3번 다음2번째 로우값을 출력 값이 없다면 0
  FROM emp
;

RATIO_TO_REPORT (점유율)

RATIO_TO_REPORT 함수는 합에 대한 값의 비율을 계산한다. 아래 예제를 통해서 RATIO_TO_REPORT 함수에 대해 이해해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT deptno
     , SUM(sal) sal
     , SUM(SUM(sal)) OVER() tot
     , ROUND(SUM(sal) /  SUM(SUM(sal)) OVER(), 2) rat1
     , ROUND(RATIO_TO_REPORT(SUM(sal)) OVER(), 2) rat2
  FROM emp
 GROUP BY deptno
;
 
 
 DEPTNO        SAL        TOT       RAT1       RAT2
------- ---------- ---------- ---------- ----------
     30       9400      29025        .32        .32
     20      10875      29025        .37        .37
     10       8750      29025         .3         .3

위 예제에 대해서 좀 더 설명하면 아래와 같다.

  • - SAL : 부서별 급여 합계를 집계함수를 사용하여 계산한 결과이다.
  • - TOT : SUM 분석함수를 이용하여 부서별 급여 합계의 전체 합계를 계산한 결과이다.
  • - RAT1 : 집계함수를 이용해서 계산한 부서별 합계에서 분석함수를 이용해 계산한 전체 합계를 나누어 비율을 계산한 결과이다.
  • - RAT2 : RATIO_TO_REPORT 분석함수를 사용하여 부서별 급여 합계의 비율을 계산한 결과이다.

집계함수와 분석함수의 중첩 사용
  • - 분석함수는 GROUP BY 보다 나중에 실행된다.
  • - 따라서 GROUP BY의 결과Set을 대상으로 분석함수 사용이 가능하다.
  • - 반대로 분석함수를 집계함수 안에서 사용할 수는 없다. 예) SUM( SUM(sal) OVER() ) 에러발생

분석:순서대로 보기 바람.

SELECT deptno
     , SUM(sal) sal //DEPTNO부서별 합
     , SUM(SUM(sal)) OVER() tot //전체의 합...
     , ROUND(SUM(sal) /  SUM(SUM(sal)) OVER(), 2) rat1 //퍼센트 나오는데 소수2자리수까지 ROUND함수.
     , ROUND(RATIO_TO_REPORT(SUM(sal)) OVER(), 2) rat2 //위와 결과는 동일함.. 소수2자리수 까지.
  FROM emp
 GROUP BY deptno

FIRST_VALUE, LAST_VALUE

  • FIRST_VALUE : 정렬된 값 중에서 첫 번째 값을 반환한다.
  • LAST_VALUE : 정렬된 값 중에서 맨 마지막 값을 반환한다.

아래 예제는 사원순 정렬의 첫번째 사원 급여(F_EMP)와 마지막 사원 급여(L_EMP)를 조회하는 예이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SELECT empno
     , sal
     , FIRST_VALUE(sal) OVER(ORDER BY empno) f_emp
     , LAST_VALUE (sal) OVER(ORDER BY empno) l_emp
  FROM emp;
 
 
 
 EMPNO        SAL      F_EMP      L_EMP
------ ---------- ---------- ----------
  7369        800        800        800
  7499       1600        800       1600
  7521       1250        800       1250
  7566       2975        800       2975
  7654       1250        800       1250
  7698       2850        800       2850
  7782       2450        800       2450
  7788       3000        800       3000
  7839       5000        800       5000
  7844       1500        800       1500
  7876       1100        800       1100
  7900        950        800        950
  7902       3000        800       3000
  7934       1300        800       1300

ORDER BY 사용시 분석함수의 기본 계산 범위는 처음부터 현재까지 이다.

분석:순서대로 보기 바람

SELECT empno
     , sal
     , FIRST_VALUE(sal) OVER(ORDER BY empno) f_emp //1번 전체 로우중에서 처번째 로우 값
     , LAST_VALUE (sal) OVER(ORDER BY empno) l_emp //2번 전체 로우중 마지막 로우 값
  FROM emp;


LAST_VALUE 직전값 대체

LAST_VALUE 사용시 값이 없을 경우 이전 값을 참조하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
WITH t AS
(
SELECT 1 no, 10 v FROM dual
UNION ALL SELECT 2, Null FROM dual
UNION ALL SELECT 3, Null FROM dual
UNION ALL SELECT 4, 20   FROM dual
UNION ALL SELECT 5, 10   FROM dual
UNION ALL SELECT 6, Null FROM dual
UNION ALL SELECT 7, Null FROM dual
UNION ALL SELECT 8, Null FROM dual
UNION ALL SELECT 9, 40   FROM dual
)
SELECT no, v
     , NVL(v, LAG(v) OVER(ORDER BY no)) v1
     , LAST_VALUE(v) OVER(ORDER BY no)  v2
     , LAST_VALUE(v IGNORE NULLS) OVER(ORDER BY no) v3
  FROM t
;
 
-- V3 컬럼의 경우 모든 값이 조회되는 것을 확인 할 수 있다.
   NO          V         V1         V2         V3
----- ---------- ---------- ---------- ----------
    1         10         10         10         10
    2                    10                    10
    3                                          10
    4         20         20         20         20
    5         10         10         10         10
    6                    10                    10
    7                                          10
    8                                          10
    9         40         40         40         40

IGNORE NULLS : NULL 을 제외한 마지막 값
SELECT no, v
     , NVL(v, LAG(v) OVER(ORDER BY no)) v1 //1번 null일때 v의 이전 값을 읽어옴 결국엔 null도 나올수 있음
     , LAST_VALUE(v) OVER(ORDER BY no)  v2 //2번 다음 로우 값을 읽어옴 null도 나올수 있음
     , LAST_VALUE(v IGNORE NULLS) OVER(ORDER BY no) v3 //3번 이건 IGNORE NULLS 이것이 null을 제외한 마지막 값을 가르킴..
  FROM t

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2675
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

Rollup  (0) 2014.12.03
KEEP  (0) 2014.12.03
윈도우 함수 WINDOWNING PRECEDING  (0) 2014.12.03
집계함수 -> 분석함수 사용하기  (0) 2014.12.03
순위함수 RANK DENSE_RANK ROW_NUMBER 특징별 기억하면 좋고  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

윈도우 함수란

  • - 분석함수 중에서 윈도우절(WINDOWNING 절)을 사용하는 함수를 윈도우 함수라고 한다.
  • - 윈도우절을 사용하면 PARTITION BY 절에 명시된 그룹을 좀 더 세부적으로 그룹핑 할 수 있다.
  • - 윈도우절은 분석함수중에서 일부(AVG, COUNT, SUM, MAX, MIN)만 사용 할 수 있다.

WINDOWNING 절 Syntax
1
2
3
4
5
6
윈도우 함수 OVER (
        PARTITION BY
            ORDER BY 절 [ASC|DESC]
        ROWS | RANGE
        BETWEEN UNBOUNDED PRECEDING | n PRECEDING | CURRENT ROW
            AND UNBOUNDED FOLLOWING | n FOLLOWING | CURRENT ROW

  • - ROWS : 물리적인 ROW 단위로 행 집합을 지정한다.
  • - RANGE : 논리적인 상대번지로 행 집합을 지정한다.
  • - BETWEEN ~ AND 절 : 윈도우의 시작과 끝 위치를 지정한다.
  • - UNBOUNDED PRECEDING : PARTITION의 첫 번째 로우에서 윈도우가 시작한다.
  • - UNBOUNDED FOLLOWING : PARTITION의 마지막 로우에서 윈도우가 시작한다.
  • - CURRENT ROW : 윈도우의 시작이나 끝 위치가 현재 로우 이다.

WINDOWING 절 예제

ROWS 사용 예제1

아래는 부서별(PARTITION BY deptno)로 이전 ROW(ROWS 1 PRECEDING)의 급여와 현재 ROW의 급여 합계를 출력하는 예제이다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SELECT empno, ename, deptno, sal,
       SUM(sal) OVER (PARTITION BY deptno
                          ORDER BY empno
                           ROWS 1 PRECEDING ) pre_sum
  FROM emp;
 
 
-- PRE_SUM : 이전 ROW와 현재 ROW의 급여 합계가 출력된 것을 확인 할 수 있다.
 EMPNO ENAME       DEPTNO        SAL    PRE_SUM
------ ------- ---------- ---------- ----------
  7782 CLARK           10       2450       2450
  7839 KING            10       5000       7450
  7934 MILLER          10       1300       6300
  7369 SMITH           20        800        800
  7566 JONES           20       2975       3775
  7788 SCOTT           20       3000       5975
  7876 ADAMS           20       1100       4100
  7902 FORD            20       3000       4100
  7499 ALLEN           30       1600       1600
  7521 WARD            30       1250       2850
  7654 MARTIN          30       1250       2500
  7698 BLAKE           30       2850       4100
  7844 TURNER          30       1500       4350
  7900 JAMES           30        950       2450

이쿼리 분석: 순번대로 보기 바람.

SELECT empno, ename, deptno, sal, 

       SUM(sal) OVER (PARTITION BY deptno  //1번 부서별로 그룹을 맺으며

                          ORDER BY empno //2번 정렬은 사번으로.

                           ROWS 1 PRECEDING ) pre_sum //3번 이전 로우1개와의 합을 pre_sum으로 출력

  FROM emp;

ROWS 사용 예제2

아래 예제는 첫 번째 ROW부터 마지막 ROW까지의 합과(SAL1), 첫 번째 ROW부터 현재 ROW까지의 합(SAL2) 그리고 현재 ROW부터 마지막 ROW까지의 합(SAL3)을 출력하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
SELECT empno, ename, deptno, sal,
       SUM(sal) OVER(ORDER BY deptno, empno
                ROWS BETWEEN UNBOUNDED PRECEDING
                         AND UNBOUNDED FOLLOWING) sal1,
       SUM(sal) OVER(ORDER BY deptno, empno
                ROWS BETWEEN UNBOUNDED PRECEDING
                         AND CURRENT ROW) sal2,
       SUM(sal) OVER(ORDER BY deptno, empno
                ROWS BETWEEN CURRENT ROW
                         AND UNBOUNDED FOLLOWING) sal3
  FROM emp;
 
 
-- SAL1 : 첫 번째 ROW부터 마지막 ROW까지의 급여 합계이다.
-- SAL2 : 첫 번째 ROW 부터 현재 ROW까지의 급여 합계이다.
-- SAL3 : 현재 ROW부터 마지막 ROW까지 급여 합계이다.
 EMPNO ENAME       DEPTNO        SAL       SAL1       SAL2       SAL3
------ ------- ---------- ---------- ---------- ---------- ----------
  7782 CLARK           10       2450      29025       2450      29025
  7839 KING            10       5000      29025       7450      26575
  7934 MILLER          10       1300      29025       8750      21575
  7369 SMITH           20        800      29025       9550      20275
  7566 JONES           20       2975      29025      12525      19475
  7788 SCOTT           20       3000      29025      15525      16500
  7876 ADAMS           20       1100      29025      16625      13500
  7902 FORD            20       3000      29025      19625      12400
  7499 ALLEN           30       1600      29025      21225       9400
  7521 WARD            30       1250      29025      22475       7800
  7654 MARTIN          30       1250      29025      23725       6550
  7698 BLAKE           30       2850      29025      26575       5300
  7844 TURNER          30       1500      29025      28075       2450
  7900 JAMES           30        950      29025      29025        950

이쿼리 분석: 순서대로 보기 바람.

SELECT empno, ename, deptno, sal,
       SUM(sal) OVER(ORDER BY deptno, empno
                ROWS BETWEEN UNBOUNDED PRECEDING
                         AND UNBOUNDED FOLLOWING) sal1,//1번 위에서 정의되어 있다시피 처음부터 마지막로우까지의 합을 deptno가 우선 그담 사원번호순으로 정렬하여 출력.
       SUM(sal) OVER(ORDER BY deptno, empno
                ROWS BETWEEN UNBOUNDED PRECEDING
                         AND CURRENT ROW) sal2, //2번 처음부터 현재 로우까지의 합.정렬은 위와 동일
       SUM(sal) OVER(ORDER BY deptno, empno
                ROWS BETWEEN CURRENT ROW
                         AND UNBOUNDED FOLLOWING) sal3 //3번 현재로우부터 마지막로우까지의 합 정렬은 위와동일.
  FROM emp;


RANGE 사용 예제

아래는 월별 금액 리스트를 출력하고, 직전 3개월 합계(AMT_PRE3)와 이후 3개월 합계(AMT_FOL3)를 함께 표시하는 예제이다.

아래 예제에서는 7월 데이터가 없기 때문에 직전 3개월 합계(AMT_PRE3) 8월의 경우 6월,5월 두 달치만 누적된 것을 확인 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
WITH test AS
(
SELECT '200801' yyyymm, 100 amt FROM dual
UNION ALL SELECT '200802', 200 FROM dual
UNION ALL SELECT '200803', 300 FROM dual
UNION ALL SELECT '200804', 400 FROM dual
UNION ALL SELECT '200805', 500 FROM dual
UNION ALL SELECT '200806', 600 FROM dual
UNION ALL SELECT '200808', 800 FROM dual
UNION ALL SELECT '200809', 900 FROM dual
UNION ALL SELECT '200810', 100 FROM dual
UNION ALL SELECT '200811', 200 FROM dual
UNION ALL SELECT '200812', 300 FROM dual
)
SELECT yyyymm
     , amt
     , SUM(amt) OVER(ORDER BY TO_DATE(yyyymm,'yyyymm')
                RANGE BETWEEN INTERVAL '3' MONTH PRECEDING
                          AND INTERVAL '1' MONTH PRECEDING) amt_pre3
     , SUM(amt) OVER(ORDER BY TO_DATE(yyyymm,'yyyymm')
                RANGE BETWEEN INTERVAL '1' MONTH FOLLOWING
                          AND INTERVAL '3' MONTH FOLLOWING) amt_fol3
  FROM test
;
 
-- AMT_PRE3 : 직전 3개월 합계
-- AMT_FOL3 : 이후 3개월 합계
YYYYMM           AMT   AMT_PRE3   AMT_FOL3
--------- ---------- ---------- ----------
200801           100                   900
200802           200        100       1200
200803           300        300       1500
200804           400        600       1100
200805           500        900       1400
200806           600       1200       1700
200808           800       1100       1200
200809           900       1400        600
200810           100       1700        500
200811           200       1800        300
200812           300       1200

분석:순서대로 보기 바람. //좀힘들었음.

SELECT yyyymm

     , amt

     , SUM(amt) OVER(ORDER BY TO_DATE(yyyymm,'yyyymm')

                RANGE BETWEEN INTERVAL '3' MONTH PRECEDING

                          AND INTERVAL '1' MONTH PRECEDING) amt_pre3 //1번 시작이 3개월 전부터  1개얼 전까지의 합임 정렬은 당연히 날짜순.. 

     , SUM(amt) OVER(ORDER BY TO_DATE(yyyymm,'yyyymm')

                RANGE BETWEEN INTERVAL '1' MONTH FOLLOWING

                          AND INTERVAL '3' MONTH FOLLOWING) amt_fol3 //2번 1개월후부터 3개월후까지의 합 정렬은 날짜순 

  FROM test

;

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2674
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


'Oracle' 카테고리의 다른 글

KEEP  (0) 2014.12.03
LAG, LEAD (다른 행의 값을 참조)  (0) 2014.12.03
집계함수 -> 분석함수 사용하기  (0) 2014.12.03
순위함수 RANK DENSE_RANK ROW_NUMBER 특징별 기억하면 좋고  (0) 2014.12.03
집계함수와 분석함수  (0) 2014.12.03
블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

SUM, MIN, MAX, AVG, COUNT등의 집계 함수도 분석함수로 사용할 수 있다.

SUM (누적합계)

아래는 사원의 전체급여 합계(all_sum), 부서별 급여 합계(dept_sum), 부서별로 누적 합계(nujuk_sum)를 조회하는 예이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT empno, ename, deptno,      
       SUM(sal) OVER () all_sum,
       SUM(sal) OVER (PARTITION BY deptno) dept_sum,
       SUM(sal) OVER (PARTITION BY deptno ORDER BY empno) nujuk_sum
 FROM emp;
 
 
 EMPNO ENAME       DEPTNO    ALL_SUM   DEPT_SUM  NUJUK_SUM
------ ------- ---------- ---------- ---------- ----------
  7782 CLARK           10      29025       8750       2450
  7839 KING            10      29025       8750       7450
  7934 MILLER          10      29025       8750       8750
  7369 SMITH           20      29025      10875        800
  7566 JONES           20      29025      10875       3775
  7788 SCOTT           20      29025      10875       6775
  7876 ADAMS           20      29025      10875       7875
  7902 FORD            20      29025      10875      10875
  7499 ALLEN           30      29025       9400       1600
  7521 WARD            30      29025       9400       2850
  7654 MARTIN          30      29025       9400       4100
  7698 BLAKE           30      29025       9400       6950
  7844 TURNER          30      29025       9400       8450
  7900 JAMES           30      29025       9400       9400
  • - ALL_SUM : PARTITION BY절과 ORDER BY절이 생략되어 전체 급여 합계를 계산한다.
  • - DEPT_SUM : PARTITION BY절에 deptno를 사용하여 부서별 급여 합계를 계산한다.
  • - NUJUK_SUM : 부서별로 구분하고, empno로 ORDER BY절을 사용하였다. 사원번호 별로 급여 합계가 누적되어 계산되는 것을 확인 할 수 있다.
분석함수 OVER절 안에서 ORDER BY절을 사용하면 ORDER BY 절의 컬럼을 기준으로 누적되어 계산 된다는 것을 확인 할 수 있다.

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2673
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,

순위함수

  • RANK 함수는 순위를 부여하는 함수로 동일순위 처리가 가능하다. (중복 순위 다음 순서 건너뜀 - 1,2,2,4)
  • DENSE_RANK 함수는 RANK 함수와 같은 역할을 하지만 동일 등수가 순위에 영향이 없다.(중복순위 다음 순위 연속 - 1,2,2,3)
  • ROW_NUMBER 함수는 특정 순위로 일련번호를 제공하는 함수로 동일순위 처리가 불가능하다. (중복순위 없이 유일값 - 1,2,3,4)
  • - 순위 함수 사용시 ORDER BY절은 필수로 입력해야 한다.

순위함수 - RANK

아래는 급여가 높은 순서대로 순위를 구하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SELECT deptno, empno, sal
     , RANK() OVER(ORDER BY sal DESC) rk
  FROM emp
;
 
  DEPTNO      EMPNO        SAL         RK
-------- ---------- ---------- ----------
      10       7839       5000          1
      20       7788       3000          2
      20       7902       3000          2
      20       7566       2975          4
      30       7698       2850          5
      10       7782       2450          6
      30       7499       1600          7
      30       7844       1500          8
      10       7934       1300          9
      30       7521       1250         10
      30       7654       1250         10
      20       7876       1100         12
      30       7900        950         13
      20       7369        800         14

급여가 같은 경우 아래와 같이 동일 순위로 처리되는 것을 확인 할 수 있다.

  • [그림] RANK 실행결과
  • RANK 실행결과

아래는 부서별(PARTITION BY deptno)로 급여가 높은 순서대로(ORDER BY sal DESC) 순위를 구하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT deptno, empno, sal
     , RANK() OVER(PARTITION BY deptno
                       ORDER BY sal DESC) rk
  FROM emp
;
 
 
  DEPTNO      EMPNO        SAL         RK
-------- ---------- ---------- ----------
      10       7839       5000          1
      10       7782       2450          2
      10       7934       1300          3
      20       7788       3000          1
      20       7902       3000          1
      20       7566       2975          3
      20       7876       1100          4
      20       7369        800          5
      30       7698       2850          1
      30       7499       1600          2
      30       7844       1500          3
      30       7654       1250          4
      30       7521       1250          4
      30       7900        950          6

노트 : 순위함수의 특징
  • - ORDER BY는 생략할 수 없다.
  • - WINDOWING 절은 사용 할 수 없다.

순위함수 비교

아래 예제를 통해서 RANK, DENSE_RANK, ROW_NUMBER 함수의 차이점을 이해하자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT deptno, empno, sal
     , RANK()       OVER(ORDER BY sal DESC) rk
     , DENSE_RANK() OVER(ORDER BY sal DESC) dr
     , ROW_NUMBER() OVER(ORDER BY sal DESC) rn
  FROM emp
;
 
 DEPTNO      EMPNO        SAL         RK         DR         RN
------- ---------- ---------- ---------- ---------- ----------
     10       7839       5000          1          1          1
     20       7788       3000          2          2          2
     20       7902       3000          2          2          3
     20       7566       2975          4          3          4
     30       7698       2850          5          4          5
     10       7782       2450          6          5          6
     30       7499       1600          7          6          7
     30       7844       1500          8          7          8
     10       7934       1300          9          8          9
     30       7521       1250         10          9         10
     30       7654       1250         10          9         11
     20       7876       1100         12         10         12
     30       7900        950         13         11         13
     20       7369        800         14         12         14

  • [그림] 순위함수 비교 실행결과
  • 순위함수 비교 실행 결과

RANK : 중복 순위 다음 순서 건너뜀.(1,2,2,4)

DENSE_RANK : 중복순위 다음 순위 연속.(1,2,2,3)

ROW_NUMBER : 중복순위 없이 유일값. (1,2,3,4)

순위함수 - NTILE (분류)

NTILE 함수는 쿼리의 결과를 n개의 그룹으로 분류하는 기능을 제공한다. 아래 예제에서 GRP2는 두 개의 그룹으로, GRP3는 세 개의 그룹으로, GRP5는 다섯개의 그룹으로 분류하는 것을 알 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SELECT empno
     , NTILE(2) OVER(ORDER BY empno) grp2
     , NTILE(3) OVER(ORDER BY empno) grp3
     , NTILE(5) OVER(ORDER BY empno) grp5
  FROM emp
;
 
 
   EMPNO       GRP2       GRP3       GRP5
-------- ---------- ---------- ----------
    7369          1          1          1
    7499          1          1          1
    7521          1          1          1
    7566          1          1          2
    7654          1          1          2
    7698          1          2          2
    7782          1          2          3
    7788          2          2          3
    7839          2          2          3
    7844          2          2          4
    7876          2          3          4
    7900          2          3          4
    7902          2          3          5
    7934          2          3          5

NTILE : 지정한 숫자만큼의 그룹으로 분류

태그

문서에 대하여

  • - 강좌 URL : http://www.gurubee.net/lecture/2672
  • - 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
  • 구루비의 모든 강좌는 크리에이티브 커먼즈의 저작자표시-비영리-동일조건변경허락(BY-NC-SA) 라이선스에 따라 자유롭게 사용할 수 있습니다.


블로그 이미지

은호아빠

여행, 맛집, 일상, 프로그래밍, 개발자, 윈도우, 웹, jsp, spring, db, mysql, oracle, c#

,