SQL

SQL GROUP BY와 HAVING

#풀닢 2023. 1. 12. 18:00

GROUP BY

HAVING

 

SQL 처리하는 순서    5. SELECT 컬럼명 AS 별칭, 계산식, 함수식
    1. FROM 참조할 테이블명
    2. WHERE 컬럼명 | 함수식 비교 연산자 비교값
    3. GROUP BY 그룹을 묶을 컬럼명 / WHERE절 뒤에 쓰기
    4. HAVING 그룹함수식 비교연산자 비교값 / 그룹바이 뒤에쓴다
    6. ORDER BY 컬럼명 | 별칭 | 컬럼순법 정렬방식 [NULLS FIRST | LAST]
DETP_CODE 기준으로 구루핑

전체적인 결과 묶기, 각각의 코드당 카운트가 몇개 되는지 각부서만 몇명의 인원이 있는지
 ,DEPT_CODE

    GROUP BY DEPT_CODE;
SELECT
    COUNT(*)
    ,DEPT_CODE
    FROM EMPLOYEE
    GROUP BY DEPT_CODE;

 

GROUP BY절 같은 값들이 여러 개 기록 된 컬럼을 가지고 같은 값들을 하나의 그룹으로 묶는다.
GROUP BY 컬럼명 | 함수식, ... 그룹으로 묶은 값에 대해서 SELECT 절에서 그룹 함수를 사용한다.

부서별 급여 합계, 평균(점수처리), 
인원수 조회 후 부서코드 순 오름차순 정렬
    ,SUM(SALARY) 합계
    ,ROUND(AVG(SALARY)) 펑균
    ,COUNT(*) 인원수
GROUP BY DEPT_CODE
ORDER BY DEPT_CODE;
SELECT
    DEPT_CODE 부서
    ,SUM(SALARY) 합계
    ,ROUND(AVG(SALARY)) 펑균
    ,COUNT(*) 인원수
FROM EMPLOYEE
GROUP BY DEPT_CODE
ORDER BY DEPT_CODE;

ORDER BY 부서

ORDER BY 부서  
NULLS LAST, FIRST 원하는 기준으로 정렬하는 ORDER BY
컬럼 순별 ORDER BY 1 DESC NULLS LAST;
직급 코드별로 보너스를 받는 사원수를 조회하고
직급 코드 오름차순 조회
    ,COUNT(BONUS)
GROUP BY JOB_CODE
ORDER BY JOB_CODE;
SELECT
    JOB_CODE
    ,COUNT(BONUS)
FROM EMPLOYEE
GROUP BY JOB_CODE
ORDER BY JOB_CODE;

직급 코드별로 보너스를 받는 사원수를 조회하고 직급 코드 오름차순 정렬
단, 보너스를 받는 사람이 없는 직급 코드의 경우 RESULT SET에서 제외

    ,COUNT(BONUS)
WHERE BONUS IS NOT NULL
GROUP BY JOB_CODE
ORDER BY JOB_CODE;

SELECT
    JOB_CODE
    ,COUNT(BONUS)
FROM EMPLOYEE
WHERE BONUS IS NOT NULL
GROUP BY JOB_CODE
ORDER BY JOB_CODE;

GROUP BY절에 하나 이상의 그룹을 지정할 수 있다.
DEPT_CODE, JOB_CODE 기준으로 그루핑
   ,SUM(SALARY)
    ,COUNT(*)
GROUP BY DEPT_CODE
     ,JOB_CODE
ORDER BY 1;

SELECT
    DEPT_CODE
    ,JOB_CODE
    ,SUM(SALARY)
    ,COUNT(*)
FROM EMPLOYEE
GROUP BY DEPT_CODE
     ,JOB_CODE
ORDER BY 1;
GROUP BY절에 함수식을 사용할 수 있다.
SELECT절의 별칭을 사용할 수 없다.

성별 그룹으로 급여 평균(정수 처리), 합계, 인원수를 조회한 뒤 인원수를 내림차순 정렬
    DECODE(SUBSTR(EMP_NO,8,1), '1','남','2','여')AS 성별
    ,ROUND(AVG(SALARY))평균
    ,SUM(SALARY) 합계
    ,COUNT(*) 인원수
    FROM EMPLOYEE
    GROUP BY  DECODE(SUBSTR(EMP_NO,8,1), '1','남','2','여')
    ORDER BY 인원수 DESC; 

SELECT  
    DECODE(SUBSTR(EMP_NO,8,1), '1','남','2','여')AS 성별
    ,ROUND(AVG(SALARY))평균
    ,SUM(SALARY) 합계
    ,COUNT(*) 인원수
    FROM EMPLOYEE
    GROUP BY  DECODE(SUBSTR(EMP_NO,8,1), '1','남','2','여')
    ORDER BY 인원수 DESC; --ORDER BY 절은 마지막에 수행되므로 SELECT절 별칭 사용 가능
HAVING절
HAVING 컬럼명 | 함수식 비교연산자 비교값
그룹 함수로 구해올 그룹에 대해 조건을 설정할 때 사용한다. 그룹결과를 보고싶을 때
300만원 이상의 월급을 받는 사원들// 남은애들끼리 그룹핑해서 대상으로 부서별 월급 평균 계산    ,ROUND(AVG(SALARY)) 평균

    WHERE SALARY >= 3000000
    GROUP BY DEPT_CODE
    ORDER BY 1;


SELECT 
    DEPT_CODE
    ,ROUND(AVG(SALARY)) 평균
    FROM EMPLOYEE
    WHERE SALARY >= 3000000
    GROUP BY DEPT_CODE
    ORDER BY 1;
모든 직원을 대상으로 부서별 월급 평균을 구한 뒤 평균이 300만원 이상인 부서 조회
그룹함수에 대해서 조건을 세우고 싶을 때 
    ,ROUND(AVG(SALARY)) 평균

    GROUP BY DEPT_CODE
    HAVING ROUND(AVG(SALARY)) >= 3000000
    ORDER BY 1;
SELECT 
    DEPT_CODE
    ,ROUND(AVG(SALARY)) 평균
    FROM EMPLOYEE
    GROUP BY DEPT_CODE
    HAVING ROUND(AVG(SALARY)) >= 3000000
    ORDER BY 1;

집계 함수란? GROUP BY 절에서만 사용하는 함수
ROLLUP 그룹별로 중간 집계 처리를 하는 함수
그룹별로 묶인 값에 대한 중간 집계와 총 집계를 구할 떄 사용

 

SELECT
    JOB_CODE
    ,SUM(SALARY)
    FROM EMPLOYEE
    GROUP BY ROLLUP(JOB_CODE)
    ORDER BY 1;
--CUBE 그룹바이에 2개이상 나열할 때 차이가 난다.
    SELECT
    JOB_CODE
    ,SUM(SALARY)
    FROM EMPLOYEE
    GROUP BY CUBE(JOB_CODE)
    ORDER BY 1;
ROLLUP 함수는 인자로 전달한 그룹 중 가장 먼저 지정한 그룹별 합계와 총 합계를 구하는 함수   ,SUM(SALARY)

    GROUP BY ROLLUP(DEPT_CODE,JOB_CODE)
    ORDER BY 1;
SELECT
    DEPT_CODE
    ,JOB_CODE
    ,SUM(SALARY)
    FROM EMPLOYEE
    GROUP BY ROLLUP(DEPT_CODE,JOB_CODE)
    ORDER BY 1;

CUBE 함수는 그룹으로 지정 된 모든 그룹에 대한 집계와 총 합계를 구하는 함수
D1기준의 중간합계 D2에 대한 중간합계 7개의 행이 더 인출,     ,SUM(SALARY)

    GROUP BY CUBE(DEPT_CODE,JOB_CODE)
    ORDER BY 1;
    SELECT
    DEPT_CODE
    ,JOB_CODE
    ,SUM(SALARY)
    FROM EMPLOYEE
    GROUP BY CUBE(DEPT_CODE,JOB_CODE)
    ORDER BY 1;

GROUPING 함수 ROLLUP이나 COBE에 의한 산출물이 인자로 전달 받은 컬럼 집합의 산출물이면 0을 반환하고, 아니면 1을 반환하는 함수
COUNT로 중간집계한 것     ,SUM(SALARY)
    ,COUNT(*)
    ,GROUPING(DEPT_CODE)"부서별 그룹묶인 상태"
    ,GROUPING(JOB_CODE)"직급별 그룹 묶인 상태"
        FROM EMPLOYEE
    GROUP BY CUBE(DEPT_CODE,JOB_CODE)
    ORDER BY 1;
SELECT
    DEPT_CODE
    ,JOB_CODE
    ,SUM(SALARY)
    ,COUNT(*)
    ,GROUPING(DEPT_CODE)"부서별 그룹묶인 상태"
    ,GROUPING(JOB_CODE)"직급별 그룹 묶인 상태"
        FROM EMPLOYEE
    GROUP BY CUBE(DEPT_CODE,JOB_CODE)
    ORDER BY 1;
    SELECT
       NVL(DEPT_CODE, '부서없음')
     , JOB_CODE
     , SUM(SALARY)
     , CASE
         WHEN GROUPING(NVL(DEPT_CODE, '부서없음')) = 0 AND GROUPING(JOB_CODE) = 1 THEN '부서별합계'
         WHEN GROUPING(NVL(DEPT_CODE, '부서없음')) = 1 AND GROUPING(JOB_CODE) = 0 THEN '직급별합계'
         WHEN GROUPING(NVL(DEPT_CODE, '부서없음')) = 0 AND GROUPING(JOB_CODE) = 0 THEN '그룹별합계'
         ELSE '총합계'
       END 구분
  FROM EMPLOYEE
 GROUP BY CUBE(NVL(DEPT_CODE, '부서없음'), JOB_CODE)
 ORDER BY 1;

SET OPERATION(집합 연산)

UNION 여러 개의 쿼리 결과를 하나로 합치는 연산자
중복 된 영역을 제외하여 하나로 합친다.
SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE DEPT_CODE = 'D5'
    UNION
    SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE SALARY > 3000000;

UNION ALL 여러 개의 쿼리를 하나로 합치는 연산자
UNION과의 차이 중복 영역을 모두 포함시킨다는 것
SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE DEPT_CODE = 'D5'
    UNION ALL
    SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE SALARY > 3000000;

INTERSECT  여러 개의 SELECT한 결과에서 공통 부분만 결과로 추출
수학에서 교집합과 유사하다.
SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE DEPT_CODE = 'D5'
INTERSECT --요기
    SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE SALARY > 3000000;

MINUS 선행 SELECT 결과에서 후행 SELECT 결과와 겹치는 부분을 제외한 나머지만 추출, 수학에서 차집합과 유사하다.
SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE DEPT_CODE = 'D5'
MINUS --요기
    SELECT
    EMP_ID
    ,EMP_NAME
    ,DEPT_CODE
    ,SALARY
    FROM EMPLOYEE
    WHERE SALARY > 3000000;

GROUPING SET 그룹별로 처리 된 여러 개의 SELECT문을 하나로 합칠 때 사용한다.
SET OPERATION과 결과 동일,  3가지의 그룹핑 결과 합쳐놨음
SELECT
    DEPT_CODE
    ,JOB_CODE
    ,MANAGER_ID
    ,FLOOR(AVG(SALARY))
    FROM EMPLOYEE
    GROUP BY GROUPING SETS((DEPT_CODE, JOB_CODE, MANAGER_ID)
                        ,(DEPT_CODE, MANAGER_ID)
                        ,(JOB_CODE,MANAGER_ID)
                        );

 

SMALL