두근두근 공부홀릭

실무에서 사용한 SQL문

뚱기사 2010. 11. 20. 22:31

실무를 접하면서 사용했던 SQL문들이다.

 

** 특정 문자의 갯수 추출 **
select length('aaa-aa-') - length(replace('aaa-aa-','-','')) from dual;
 
 
** 문자안에서 구분자로 구분되어있는 데이터 구분해서 추출하기 **
    (필요할때..복사해서.. 사용해라!!)
 
 
select substr(aaa, 1, instr(aaa, '|')-1)||','||
       substr(aaa, instr(aaa, '|')+1, instr(aaa, '|', 1,2)-instr(aaa, '|', 1, 1)-1)||','||
       substr(aaa, instr(aaa, '|', 1, 2)+1, instr(aaa, '|', 1,3)-instr(aaa, '|', 1, 2)-1)
  from imsi_temp
 where length(aaa) - length(replace(aaa,'|','')) = 3
 
 
** 캐리지리턴 값 처리 방법 **
 캐리지 리턴 갱신시 replace(content, chr(13), '')
 라인피드 갱신시     replace(content, chr(13)&char(10),'')
 
 
** NVL2 함수 **
 
NVL2(expr,expr1,expr2);
설명) expr의 값이 null이 아닐 경우에는  expr1의 값을 반환 null일 경우에는 expr2의 값을 반환
 
예제) SELECT ename, NVL2(comm, 1, 0) FROM emp;
--> comm에 있는 값이 null이면 0, 아니면 1을 반환
 
 
** replace 를 여러번처리를 한번에 **
    (translate 함수 사용) -> 간단한 암호화 시킬때 사용할 수 있음! ^^
SELECT TRANSLATE('2KRW229',
             '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
             '9999999999XXXXXXXXXXXXXXXXXXXXXXXXXX') "License"
  FROM DUAL;

License
--------
9XXX999
 
 
** 전체 데이터 중에서 특정 비율로 데이터 추출 **
 
SELECT *  FROM table_name   SAMPLE (10);
 
 
** 한테이블에서 중복된 데이터 삭제 **
 
1) 중복된 데이터중에서 ROWID가 큰 값을 제거
  
SQL> DELETE FROM emp a
      WHERE rowid > (SELECT MIN(ROWID) 
                       FROM emp b
                      WHERE b.empno = a.empno);

  
2) 나중에 들어온 데이터를 살릴경우

SQL> DELETE FROM emp a
      WHERE ROWID < (SELECT MAX(ROWID) 
                       FROM emp b
                      WHERE a.empno = b.empno);
 
 
** 인덱스 재구성 및 분석 결과 확인 방법 **
 
1. alter index 인덱스명 rebuild;
2. analyze index 인덱스명 validate structure;
3. select blocks, btree_space, used_space, pct_used "사용율(%)", lf_rows, del_lf_rows "삭제행"
   from index_stats;
 
-- 샘플 결과 --
BLOCKS BTREE_SPACE USED_SPACE 사용율(%) LF_ROWS 삭제행
          8         24020             10532          44             613       0
--> 인덱스가 삭제된 행이 많으면 인덱스를 재구축 해야함.
--> LF_ROW에 대한 DEL_LF_ROWS의 비가 20%를 초과하면 인덱스를 재구축 해야함.
 

1. index_stats 자료사전에 결과가 저장
analyze index index_name validate structure;

2. rebuild 대상 확인.
select (DEL_LF_ROWS_LEN/LF_ROWS_LEN) * 100 as index_stat  
from index_stats;                                             

DEL_LF_ROWS_LEN : 컬럼은 인덱스 블록중 삭제되었던 행들의 전체길이 값
LF_ROWS_LEN        : 컬럼은 현재 인덱스가 리퍼 블록에 저장되어 있는 인덱스 테이터의 전체길이

INDEX_STAT                                           
----------
         0    ---> 일반적으로 20%를 초과하면 인덱스 rebuild 해주어야 성능을 기대 할수있음.

** Multiple Insert 및 MERGE 사용법 **
 
1) Multiple Insert
  => 하나의 insert문에서 여러 개의 테이블에 동시에 하나의 행을 입력할 수 있다
 
  Insert [all]
  [when 조건절1 then
      into [table1] values (col1,col2,...)]
   [when 조건절2 then
      into [table2] values (col1,col2,...)]
   [else
     into [table3] values (col1,col2,...)]
  [Sub-Query];
 
   -  Multiple Insert종류
       1) Unconditional-Insert문
          => Insert문을 실행할 때 어떤 조건도 없는 경우
           INSERT ALL
           INTO sal_history VALUES (empid, hiredate, sal)
           INTO mgr_history VALUES (empid, mgr, sal)
           SELECT employee_id empid, hire_date hiredate, salary sal, manager_id mgr
               FROM employees
              WHERE employee_id > 200 ;
 
       2) Conditional-Insert문
          => Insert문을 실행할 때 어떤 조건을 만족하는 행만을 입력하는 경우
              INSERT ALL
              WHEN sal > 10000 THEN
                      INTO sal_history VALUES (empid, hiredate, sal)
              WHEN mgr > 200 THEN
                     INTO mgr_history VALUES (empid, mgr, sal)
              SELECT employee_id empid, hire_date hiredate, salary sal, manager_id mgr
                FROM employees
              WHERE employee_id > 200 ;
 
       3) CONDITIONAL-FIRST INSERT문
            => 서브쿼리에 의해 리턴된 데이타가 INSERT문에 정의된 첫번째 조건을 만족하면
               그 조건에 의해 데이터를 입력하고 만족하지 않으면 그 다음에 정의된 조건에 의해
               데이터를 입력시키는 방법
               INSERT FIRST
               WHEN sal > 25000 THEN
                  INTO special_sal VALUES (deptid, sal)
               WHEN hiredate like ('%00%') THEN
                  INTO hiredate_history VALUES (deptid, hiredate)
               WHEN hiredate like ('%99%') THEN
                  INTO hiredate_history VALUES (deptid, hiredate)
               ELSE
                  INTO hiredate_history VALUES (deptid, hiredate)
               SELECT departement_id deptid, sum(salary) sal,
                      max(hire_date) hiredate
                 FROM employees
                GROUP BY deptid ;
 
          4) PIVOTING-INSERT문
             => 안 쓸 거 같음
 
2) MERGE문 (Oracle 9i에서 새롭게 추가됨)
  => DML(INSERT, UPDATE, DELETE)문들의 단점은 하나의 SQL문을 작성해야 하고
     데이터를 입력할 때 이미 존재하는 데이터가 테이블 내에 존재할 때는 에러가 발생하고
     다시 UPDATE문을 실행하여 데이터를 변경해야만 했다.
     MERGE문은 새롭게 입력하는 데이터가 테이블 내에 존재하지 않으면 INSERT되고
     존재하면 UPDATE문을 실행할 수 있습니다.
 
         MERGE INTO [table명] [테이블 별칭]
         USING [대상table/view] [대상table/view별칭]
         on [join 조건]

         WHEN MATCHED THEN
              UPDATE SET col1 = values1 ,
                         col2 = values2
          WHEN NOT MATCHED THEN
              INSERT (column명, , ,)
              VALUES (value1, value2, ...);
             
             
          MERGE INTO copy_emp c
                USING employee e
                on (c.employee_id = e.employee_id)
           WHEN MATCHED THEN
                UPDATE SET c.first_name  = e.first_name,
                           c.last_name   = e.last_name,
                           c.email       = e.email
           WHEN NOT MATCHED THEN
                INSERT VALUES (e.employee_id, e.first_name, e.last_name, e.email) ;
 
  ** 참고로 Merge INTO에서 where 조건절과 Update 컬럼이 동일해서는 안된다..
     만약 같을 경우에는 문법 오류가 발생한다.

 

** Rank Function **
 

오라클에서는 RANK Function을 사용해서 순위를 간편하게 부여할 수 있습니다.
 
RANK Function는 oracle 8i(8.1.6) 부터 가능합니다.
8.1.6 이전 버전에서는 사용 할 수 없습니다. ORA-923 error 가 발생 합니다.
 
plsql 내에서는 oracle 9i 부터 가능합니다.  8.1.6에서는 ORA-900 error가 발생 합니다.
 
-- scott유저로 접속을 합니다.
SQLPLUS scott/tiger
 

-- RANK() 함수를 사용하여 급여 순으로 순위를 부여한 예제입니다. 
-- RK의 출력값을 보면 급여가 같으면 같은 순위로 부여가 됩니다.

SQL>SELECT empno, ename, sal,
        RANK() OVER( ORDER BY sal DESC ) as rk
        FROM emp;


    EMPNO ENAME             SAL         RK
--------- ---------- ---------- ----------
     7839 KING             5000          1
     7788 SCOTT            3000          2
     7902 FORD             3000          2
     7566 JONES            2975          4
     7698 BLAKE            2850          5
     7782 CLARK            2450          6
     7499 ALLEN            1600          7
     7844 TURNER           1500          8
     7934 MILLER           1300          9
     7521 WARD             1250         10
     7654 MARTIN           1250         10
     7876 ADAMS            1100         12
     7900 JAMES             950         13
     7369 SMITH             800         14



☞ 그룹별로 순위를 부여 하는 법

-- 위 예제는 deptno를 파티션으로 나누어서 부서별로 순위를 부여 합니다.
-- 특정한 그룹별로 순위를 부여하고 싶을때 사용 하면 편합니다.

SQL>SELECT deptno, ename, sal,
       RANK() OVER (PARTITION BY deptno ORDER BY sal DESC ) as rk
       FROM emp ;
 
 DEPTNO ENAME             SAL        RK
------- ---------- ---------- ---------
     10 KING             5000         1
     10 CLARK            2450         2
     10 MILLER           1300         3
     20 SCOTT            3000         1
     20 FORD             3000         1
     20 JONES            2975         3
     20 ADAMS            1100         4
     20 SMITH             800         5
     30 BLAKE            2850         1
     30 ALLEN            1600         2
     30 TURNER           1500         3
     30 WARD             1250         4
     30 MARTIN           1250         4
     30 JAMES             950         6

 


☞ DENSE_RANK() 함수

 DENSE_RANK( ) - 중복 RANK의 수와 무관하게 numbering을 합니다.

-- 1등, 2등, 2등 이렇게 2등이 중복되었는데 4등이 아니라 3등이 부여 됩니다.

SQL>SELECT empno, ename, sal, 
       DENSE_RANK() OVER (ORDER BY sal DESC ) as rk
       FROM emp;    
   
    EMPNO ENAME             SAL        RK
--------- ---------- ---------- ---------
     7839 KING             5000         1
     7788 SCOTT            3000         2
     7902 FORD             3000         2
     7566 JONES            2975         3
     7698 BLAKE            2850         4
     7782 CLARK            2450         5
     7499 ALLEN            1600         6
     7844 TURNER           1500         7
     7934 MILLER           1300         8
     7521 WARD             1250         9
     7654 MARTIN           1250         9
     7876 ADAMS            1100        10
     7900 JAMES             950        11
     7369 SMITH             800        12
 

 
 
 
** Connect by **

Connect by 계층적 쿼리는 오라클만이 가진 기능 중 하나로, 데이터를 선택하여 계층적인 순서 그대로 리턴하는데 사용된다.
예를 들면,  아래와 같이 직원 테이블이 있다고 생각 하자.

직원   직속상사      직급
--------------------
철수     순희         대리
순희     영희         과장
길동     순희         대리
영희     개똥         부장
개똥                       사장

기본적인 SQl을 사용하여 계층 관계를 표현하는것은 불가능하다. 하지만 재귀 PL/SQL 루틴connect by
를 사용한다면 표현이 가능하다.
재귀 PL/SQL은개발과 처리 과정에서 다소 많은 시간이 필요로 한다는 단점이 있으며, 변경사항이 있을 때 다른 저장 프로시저를 만들거나 보다 복잡하게 변경해야한다는 점도 무시 할수 없다.
이에 오라클에서는 connect by라는 확장된 select 구문을 지원한다.

기본형식

Select lpad(' ',(level-1)*2,' ')||직원 직원, 직급

  From 직원
Start With 직원 = '개똥'
Connect by 직속상사 = prior 직원

   직원      직급
-------------
개똥         사장
  영희       부장
    순희     과장
      철수   대리
      길동   대리

start with
select 구문의 start with 절은 계층 구조가 어떤 행에서 시작하는지 지정하는 기능을 한다.
정의 : start with <조건>
where 절의 내용으로 쓸 수 있는 조건이라면 start with로도 사용이 가능하며, 하나 이상의 조건을 결함하는 것도 가능하다.
 ex) start with 직원 ='개똥'and 직원 ='순희'
start with 적의 조건에 맞는 행은 결과셋의 루트 노드가 된다. 주의할점은 조건에 맞는 행이 한 번 이상 등장할 경우이다.
예를 들면 start with 직원 ='개똥'and 직원 ='순희' 사용하면 개똥 이 순희 하위에 있기 때문에 순희 트리가 두 번 만들어지게 된다.
(한번은 개똥의 하위에서, 그리고 한 번은 루트로서)

select lpad(' ',(level-1)*2,' ')||직원 직원, 직급
  from 직원
start with 직원 = '개똥' or 직원 ='순희'
connect by 직속상사 = prior 직원
   직원      직급

-------------
순희         과장
  철수       대리
 
길동       대리
개똥         사장
  영희       부장
   
순희     과장
      철수   대리
      길동   대리


같은 결과셋이 여러 번 만들어지는 것을 방지하기 위해서는 이러한 조건을 사용해서는 안 된다.

처음 쿼리의 예제에서 직원 ='개똥'이라는 조건을 사용했으며, 이는 회사의 가장 높은 사람을 의미하는 것으로 전체 직원에 대한 목록이 만들어 진다. 하지만 이러한 방법은 그다지 좋지 않다. 왜냐하면, 개똥이 테이블에서 빠져나간다면 새로운 쿼리를 작성하여 직속상사가 의 값이 NULL 인 직원으로 부터 루트 노드가 다시 시작되도록 해야할 것이다.


그러므로, 가능하면 보다 구체적인, 즉 결과셋의 양이 적은 조건을 사용하는 것이 바람직하다. 직원 테이블을 보면 개똥의 직속상사의 값이 NULL로 저장되어 있는데, 이는 개똥이라는 직원이 보고할 사람이 없음을, 즉 가장 최상의 간부임을 의미한다.

select lpad(' ',(level-1)*2,' ')||직원 직원, 직급
  from 직원
start with 직속상사 is null
connect by 직속상사 = prior 직원

   직원      직급
-------------
개똥         사장
  영희       부장
    순희     과장
      철수   대리
      길동   대리



Connect by Prior

connect by 절은 각 행이 어떻게 연결되는지를 오라클에게 알려주는 역할을 한다. 즉 계층 구조 내에서 각 행의 관계를 설정하는 것이다.
현재 행과 다른 행은 Prior라는 키워드를 통해 구별된다. Prior는 상위 행을 참조하는 것으로, 우리의 예제에서는 다음과 같이 사용되었다.
 
connect by 직속상사 = prior 직원
이는 "방금 전 행의 직원 값이 현재 행의 직속상사 값인 모든 행을 찾아라"라는 의미이다.
쉽게 말하면, 방금전에 살펴본 직원이 현재 직원의 상사가 되는 방식으로 리턴하라는 것이다.
다음 예제 코드를 보면, prior 부분이 = 기호를 사이에 두고 반대편으로 건너갔는데, 결과는 다음과 같이 트리를 거슬러 내려가는 것이 아니라, 거슬러 올라가는 방식으로 리턴되었다.

select lpad(' ',(level-1)*2,' ')||직원 직원, 직급
  from 직원
start with 직원 ='철수'
connect by prior 직속상사 = 직원


   직원      직급
-------------
철수         대리
  순희       과장
    영희     부장
      개똥   사장

이 쿼리에서는 철수가 루트 노드이며, 그의 상사가 오히려 아래에 표현되어 있다. 그 이유는 " 방금 전 행의 직속상사 값이 현재 행의 직원 값인 모든 행을 찾아라"라고 선언했기 때문이다. 이와 같이 prior 키워드를 등호의 반대편으로 넣어도 오류가 발생하지 않고, 전혀 다른 결과가 얻어짐을 알 수 있다.

prior 키워드는 또한 이전 행의 열을 참조하기 위해 다음과 같이 select 절 내에서 사용 될 수도 있다.

select lpad(' ',(level-1)*2,' ')||직원 직원,
prior 직원 상사 ,직급
  from 직원
start with 직원 ='철수'
connect by prior 직속상사 = 직원

   직원      상사   직급
-------------------
철수                   대리
  순희       철수   과장
    영희     순희   부장
      개똥   영희   사장

여기서는 직원과 직속상사의 이름을 동시에 선택하였는데, 사실 두 값은 같은 행에 존재하는 것이 아니기 때문에 평범한 방법으로는 이와 같은 결과를 얻을 수 없다. 그래서 예제에서는 두 행을 동시 접근하여 각각 값을 얻어낸 것이다.

Level
level은 오라클에서 실행되는 모든 쿼리 내에서 사용 가능한 가상-열로서, 트리 내에서 어떤 단계(level)에 있는지를 나타내는 정수값이다.
계층적인 쿼리가 아니라면 다음과 같이 모든 값이 0, 즉 같은 단계를 가질 것이다.

select 직원,level
  from 직원

 직원  level
-----------
 철수     0
 순희     0
 길동     0
 영희     0
 개똥     0

한편, 계층적 쿼리에서는 level의 값을 통해 트리에서의 위치를 확인할 수 있다. 루트 노드의 level 값이 1이다.

select lpad(' ',(level-1)*2,' ')||직원 직원,직급,level
  from 직원
start with 직속상사 is null
connect by prior 직원 = 직속상사


   직원      직급   level
-------------------
개똥         사장      1
  영희       부장      2
    순희     과장      3
      철수   대리      4
      길동   대리      4

  트리를 한 단계씩 거슬러 내려갈 때마다 값이 1씩 증가함을 알 수 있다.

level은 여러 가지 면에서 아주 유용하다. 먼저, 다음과 같이 각 항목을 출력할 때 앞에 붙는 공백의 양을 조절하여 계층적인 형식을 한눈에 알아볼 수 있도록 하는 것이 가능하다.

 selectlpad(' ',(level-1)*2,' ')||직원 직원

또한, level 값이 3까지인 내용만을 출력하라. 등의 명령도 가능하다.

select lpad(' ',(level-1)*2,' ')||직원 직원,직급,level
  from 직원
start with 직속상사 is null
connect by prior 직원 = 직속상사 and level <= 3


   직원      직급   level
-------------------
개똥         사장      1
  영희       부장      2
    순희     과장      3


철수와 길동의 경우는 level 값이 4이기 때문에 출력되지 않았다.
level <=3 이라는 조건을 where 절이 아닌 connect by 절에 넣은 것에 주의해야한다.  어떤 곳에 넣어도 결과는 같지만, where 절에 넣으면 전체 트리를 구성한 후에 다시 선택하는 반면, connect by 절에 넣으면 이 조건을 사용해서 트리를 구성하기 때문에 보다 효과적이라고 할 수 있다.

Order siblings by

계층적쿼리에서 order by로 정렬을 하려고 하면 트리를 만든 다음에 다시 정렬을 하기 때문에 계층적인 순서가 엉커버린다.
이러한 결과를 피하기 위해서 9i 부터 siblings by 절을 사용하면 각 계층내의 데이터만을 정렬시킬수 있다.

select lpad(' ',(level-1)*2,' ')||직원 직원, 직급
  from 직원
start with 직원 = '개똥'
connect by 직속상사 = prior 직원
order by 직원

   직원     직급
-------------
      길동   대리
      철수   대리
    순희     과장
  영희       부장
개똥         사장

-> 계층을 만든후에 직원이름을 기준으로 정렬된다.

select lpad(' ',(level-1)*2,' ')||직원 직원, 직급
  from 직원
start with 직원 = '개똥'
connect by 직속상사 = prior 직원
order siblings by 직원


   직원     직급
-------------
개똥       사장
  영희     부장
    순희   과장
      길동 대리
      철수 대리

  -> 길동과 철수가 같은 level이기 때문에 정렬이 된다.

Sys_connect_by_path()

9i부터 사용되는 함수로써 계층적인 쿼리를 실행할 때 이 함수를 사용하면 루트에서 끝 노드까지 전체 경로를 리턴할 수 있게 해준다.

형식 : Sys_connect_by_path( <열>,<분리문자> )

select lpad(' ',(level-1)*2,' ')||직원 직원, 직급,Sys_connect_by_path(직원,'-') 경로
  from 직원
start with 직원 = '개똥'
connect by 직속상사 = prior 직원
order siblings by 직원

   직원       직급               경로
----------------------------------
개똥         사장    
-개똥
  영희       부장    
-개똥-영희
    순희     과장    
-개똥-영희-순희
      길동   대리    
-개똥-영희-순희-길동
      철수   대리    
-개똥-영희-순희-철수

 

 

** Grouping sets 함수 **

 

grouping sets 함수는 GROUP BY 절에서 그룹 조건을 여러 개 지정할 수 있는 함수이다.
GROUPING SETS 함수의 결과는 각 그룹 조건에 대해 별도로 GROUP BY한 결과를
UNION ALL한 결과와 동일하다.
GROUPING SETS 함수는 하나의 SQL문에 의해 여러 개의 그룹 조건을 한꺼번에 지정하여
복잡한 그룹 처리 과정을 단순하게 구성할 수 있다.

Grouping sets 함수는 Group by의 확장된 형태로 하나의 쿼리문에서 원하는
그룹핑 조건을 여러 개 기술할 수 있으며, grouping sets 함수 사용이 불가능한
이전 버전에서 복잡한 union all 연산자를 사용하여 기술하던 것을 간단하게
한 문장 안에서 해결할 수 있어 검색시 효율성이 증대 된다.
다시 말해서, grouping sets 함수를 사용하면, group by ... union all을
사용한 것보다 SQL 문이 간단해지고 또한 실행시 성능이 빨라진다.

【형식】
SELECT 컬럼명,그룹함수(컬럼명), GROUPING(컬럼명)
  FROM 테이블명
WHERE 조건
GROUP BY [ROLLUP | CUBE] 그룹핑하고자하는 컬럼명, ...
[GROUPING SETS (컬럼명,컬럼명, ...), ...]
 HAVING 그룹조건
 ORDER BY 컬럼명 또는 위치번호


【예제】

grouping sets를 사용한 경우 UNION ALL을 사용한 경우
SQL> select deptno,job,mgr,sum(sal)
  2  from emp
  3  group by GROUPING SETS((deptno,job),(deptno,mgr));
    DEPTNO JOB              MGR   SUM(SAL)
---------- --------- ---------- ----------
        10                            5000
        10                 7782       1300
        10                 7839       2450
        20                 7566       6000
        20                 7788       1100
        20                 7839       2975
        20                 7902        800
        30                 7698       5600
        10 CLERK                      1300
        10 MANAGER                    2450
        10 PRESIDENT                  5000
    DEPTNO JOB              MGR   SUM(SAL)
---------- --------- ---------- ----------
        20 CLERK                      1900
        20 ANALYST                    6000
        20 MANAGER                    2975
        30 SALEMAN                    5600
15 개의 행이 선택되었습니다.
SQL>
SQL> select deptno,job,null as mgr,sum(sal)
  2  from emp
  3  group by deptno,job
  4  UNION ALL
  5  select deptno,null as JOB,mgr,sum(sal)
  6  from emp
  7  group by deptno,mgr;
    DEPTNO JOB              MGR   SUM(SAL)
---------- --------- ---------- ----------
        10 CLERK                      1300
        10 MANAGER                    2450
        10 PRESIDENT                  5000
        20 CLERK                      1900
        20 ANALYST                    6000
        20 MANAGER                    2975
        30 SALEMAN                    5600
        10                            5000
        10                 7782       1300
        10                 7839       2450
        20                 7566       6000
    DEPTNO JOB              MGR   SUM(SAL)
---------- --------- ---------- ----------
        20                 7788       1100
        20                 7839       2975
        20                 7902        800
        30                 7698       5600
15 개의 행이 선택되었습니다.
SQL>

【예제】 SQL> select deptno,job,count(*) 2 from emp 3 group by grouping sets((deptno,job),deptno,job); DEPTNO JOB COUNT(*) ---------- --------- ---------- 10 CLERK 1 20 CLERK 2 30 CLERK 1 20 ANALYST 2 10 MANAGER 1 20 MANAGER 1 30 MANAGER 1 30 SALESMAN 4 10 PRESIDENT 1 CLERK 4 ANALYST 2 MANAGER 3 SALESMAN 4 PRESIDENT 1 10 3 20 5 30 6 17 개의 행이 선택되었습니다. SQL>

composite columns란 rollup, cube, grouping sets 절과 같은 기능을 사용하면 표현되는 각 컬럼이 하나가 아닌 복수 개의 컬럼으로 정의되는 경우이며 다음 표를 보고 이해하자.
composite column 문의 경우 group by 문의 경우
group by grouping sets(a,b,c) group by a union all
group by b union all
group by c
group by grouping sets(a,b,(b,c)) group by a union all
group by b union all
group by b,c
group by grouping sets((a,b,c)) group by a,b,c
group by grouping sets(a,(b),()) group by a union all
group by b union all
group by ()
group by grouping sets(a,rollup(b,c)) group by a union all
group by rollup(b,c)
group by rollup(a,b,c) group by (a,b,c) union all
group by (a,b) union all
group by (a) union all
group by ()
group by cube(a,b,c) group by (a,b,c) union all
group by (a,b) union all
group by (a,c) union all
group by (b,c) union all
group by (a) union all
group by (b) union all
group by (c) union all
group by ()