[ORACLE] 그룹 데이터 처리를 위한 GROUP BY와 HAVING 절 2
![[ORACLE] 그룹 데이터 처리를 위한 GROUP BY와 HAVING 절 2](/assets/img/study_Oracle/2022-09-22-%5BORACLE%5D_%EA%B7%B8%EB%A3%B9%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EC%B2%98%EB%A6%AC%EB%A5%BC%20%EC%9C%84%ED%95%9C%20GROUP%20BY%EC%99%80%20HAVING%20%EC%A0%88%202/logo.png)
그룹 데이터 처리를 위한 GROUP BY와 HAVING 절 2
집계 처리
Group data 결과 제한(Having)
-- 최고 급여가 $10,000가 넘는 각 부서의 최고 급여
  
  SELECT  department_id, MAX(salary)
    FROM  employees
GROUP BY  department_id
  HAVING  MAX(salary) > 10000;
| DEPARTMENT_ID | MAX(SALARY) | |
|---|---|---|
| 1 | 20 | 13000 | 
| 2 | 90 | 24000 | 
| 3 | 110 | 12000 | 
| 4 | 80 | 11000 | 
HAVING 절을 제외했다면 부서별 최고 급여가 출력되었을 것이다.
하지만 HAVING 절에서 최고 급여가 10000을 넘는 값만을 출력하도록 했으므로 위와 같이 출력된다.
QUIZ 1
업무별 전체 급여 합계 중 $13000 보다 큰 것만 출력하시오. 단, 업무에 REP가 포함된 것은 제외하고, 전체 급여에 대한 내림차순 정렬을 수행하시오.
  SELECT  job_id, sum(salary) PAYROLL -- 업무별 급여 합계
    FROM  employees
   WHERE  job_id NOT LIKE '%REP%' -- REP가 포함된 것은 제외
GROUP BY  job_id
  HAVING  SUM(salary) > 13000 -- $13000 보다 큰 것만
ORDER BY  SUM(salary) DESC -- 급여에 대한 내림차순 정렬
| JOB_ID | PAYROLL | |
|---|---|---|
| 1 | AD_VIP | 34000 | 
| 2 | AD_PRES | 24000 | 
| 3 | IT_PROG | 19200 | 
- Group 함수를 중첩하는 경우 반드시 Group by 절을 사용해야 한다.
 
  SELECT  MAX(AVG(salary)) -- ,department_id 가 붙게되면 오류 발생
    FROM  employees
GROUP BY  department_id;
고급(상위) 집계 처리
GROUP BY에 ROLLUP 및 CUBE 연산자 사용
- GROUP BY에 ROLLUP 또는 CUBE를 사용하여 상호 참조 열별로 대 집계 행을 생성
 - ROLLUP 그룹화는 일반 그룹화 행과 소계 값을 포함한 결과 집합을 생성
 - CUBE 그룹화는 ROLLUP에 따른 행과 교차 분석 행이 포함된 결과 집합을 생성
 
GROUP BY에 ROLLUP 사용
- ROLLUP 연산자 없이 n차원(즉, GROUP BY 절에 있는 n개의 열)에서 소계를 생성하려면 n+1개의 SELECT 문을 UNION ALL과 연결해야 한다.
 - 이렇게 하면 SELECT 문마다 테이블에 액세스하게 되므로 query가 비효율적으로 실행되므로
 - ROLLUP 연산자는 테이블에 한 번만 액세스하여 해당 결과를 수집한다.
 - 소계 새성에 관련된 열이 많을 경우에는 ROLLUP 연산자가 유용하다.
 
-- 각 부서의 급여 합계 계산
  
  SELECT  department_id, job_id, SUM(salary)
    FROM  employees
   WHERE  department_id < 60
GROUP BY  ROLLUP(department_id, job_id);
| DEPARTMENT_ID | JOB_ID | SUM(SALARY) | |
|---|---|---|---|
| 1 | 10 | AD_ASST | 4400 | 
| 2 | 10 | (null) | 4400 | 
| 3 | 50 | ST_MAN | 36400 | 
| 4 | 50 | (null) | 36400 | 
| … | |||
| 15 | (null) | (null) | 211200 | 
ROLLUP 에 의해 ‘department_id’, ‘job_id’에 대해 부분 집계 처리가 된다.
GROUP BY 절에 있는 2개(n개)의 열에서 3개(n+1)개의 그룹을 출력한다.
2행은 ‘department_id’가 10인 모든 ‘job_id’에 대한 급여 합계이며, 5행은 모든 급여 총계이다.
즉 정리하면 다음과 같다.
- 1행, 3행은 ‘department_id’와 ‘job_id’로 합계된 그룹.
 - 2행, 4행은 ‘department_id’로만 합계된 그룹
 - 5행은 총계이다.
 
GROUP BY에 CUBE 사용
- CUBE 연산자를 사용하여 단일 SELECT 문으로 교차 분석 값 생성
 - ROLLUP은 가능한 소계 조합의 일부만 생성하지만, CUBE는 GROUP BY 절에 지정된 가능한 모든 그룹화 조합의 소계와 총계를 생성
 - GROUP BY 절에 N 열이나 표현식이 있을 경우 2^n개의 가능한 대집계 조합을 생성
 - 응용 프로그램이나 프로그래밍 도구를 사용하여 이러한 대집계 값을 차트와 그래프에 제공하여 결과와 관계를 시각적이고 효율적으로 전달할 수 있다.
 
  SELECT  department_id, job_id, SUM(salary)
    FROM  employees
   WHERE  department_id < 60
GROUP BY  CUBE(department_id, job_id);
| DEPARTMENT_ID | JOB_ID | SUM(SALARY) | |
|---|---|---|---|
| 1 | (null) | (null) | 211200 | 
| 2 | (null) | HR_REP | 6500 | 
| 3 | (null) | MK_MAN | 13000 | 
| 4 | 10 | (null) | 4400 | 
| 5 | 10 | AD_ASST | 4400 | 
| 6 | 20 | (null) | 13000 | 
| 7 | 20 | MK_MAN | 13000 | 
| … | |||
| 16 | 30 | (null) | 24900 | 
GROUP BY 절에 있는 2개(n개)의 열에서 4개(2^n)개의 그룹을 출력한다.
- 1행 총계
 - 2행, 3행은 ‘job_id’로만 합계된 그룹
 - 5행, 7행은 ‘department_id’와 ‘job_id’로 합계된 그룹
 - 4행, 6행, 16행은 ‘department_id’만으로 합계된 그룹
 
ROLLUP 과 다른 점은 2번이 추가되었다는 점이다.
GROUPING 함수
- CUBE 또는 ROLLUP 연산자와 함께 사용
 - 행에서 소계를 형성하는 그룹을 찾는데 사용
 - ROLLUP 또는 CUBE로 생성된 NULL 값과 저장된 NULL 값을 구분하는데 사용
 - 0(해당 열을 이용한 group data 고려) 또는 1(고려 안함)을 반환
 
  SELECT  department_id DEPTID, job_id JOB, SUM(salary),
          GROUPING(department_id) GRP_DEPT, GROUPING(job_id) GRP_JOB
    FROM  employees
   WHERE  department_id < 50
GROUP BY  ROLLUP(department_id, job_id);
| DEPTID | JOB | SUM(SALARY) | GRP_DEPT | GRP_JOB | |
|---|---|---|---|---|---|
| 1 | 10 | AD_ASST | 4400 | 0 | 0 | 
| 2 | 10 | (null) | 4400 | 0 | 1 | 
| … | |||||
| 11 | (null) | (null) | 54800 | 1 | 1 | 
1행은 두 행을 모두 고려했기 때문에 ‘GRP_DEPT’, ‘GRP_JOB’ 가 모두 0이 출력되었다.
2행은 ‘job_id’를 고려하지 않았기 때문에 ‘GRP_DEPT’만 1이 출력되었다.
11행은 모두 집계하는 행이므로 두 행을 모두 고려하지 않았기에 둘 다 1이 출력되었다.