[ORACLE DATABASE] GROUP BY, HAVING

GROUP BY란?
➡️ 앞에서 배웠던 그룹 함수는 단 한개의 결과 값만 출력하기 때문에 그룹이 여러개일 경우 오류가 발생한다.
따라서 여러 결과값을 산출하기 위해 그룹 함수가 적용될 그룹의 기준을 GROUP BY절을 이용하여 정해 사용할 수 있다.
➡️ ROW를 특정 컬럼 기준으로 그룹화 해주는 기능, 동일한 값을 그룹으로 묶는다.
-- SELECT
-- FROM
-- [WHERE 조건식]
-- [GROUP BY 컬럼명[,컬럼명...]]
🔥 예제) 부서코드가 같은 각 부서별 급여의 합계 출력
SELECT DEPT_CODE, TO_CHAR(SUM(SALARY),'L999,999,999') AS "부서별 급여합계"
FROM EMPLOYEE
GROUP BY DEPT_CODE;

🔥 예제) 직책코드가 같은 직책별 평균 급여 조회
SELECT JOB_CODE, TO_CHAR(AVG(SALARY),'L999,999,999') AS "직책별 평균급여"
FROM EMPLOYEE
GROUP BY JOB_CODE;

🔥 예제) 부서별 평균 급여, 합계, 사원수 구하기
여기 NVL 함수를 이용하여 NULL값을 원하는 출력으로 변경할 수 있다.
NVL(컬럼명,'대체값')
NVL2(컬럴명,NULL값이 아닐 때 '대체값' , NULL값일 때 '대체값')
SELECT NVL(DEPT_CODE,'인턴'), TO_CHAR(AVG(SALARY),'L999,999,999') 평균급여, TO_CHAR(SUM(SALARY),'L999,999,999') 급여합계, COUNT(*) 사원수
FROM EMPLOYEE
GROUP BY DEPT_CODE;

🔥 예제) WHERE절과 같이 사용하기, 부서별 사원구하기
GROUP BY절을 기술하기 전 WHERE절을 이용하여 1차적으로 조건에 의해 원하는 값을 산출 후 그 결과값을 토대로 그룹화 할 수 있다. (DEPT_CODE IS NOT NULL에 따라 NULL값을 제외한 결과값을 토대로 그룹화 한다.)
SELECT DEPT_CODE, COUNT(*)
FROM EMPLOYEE
WHERE DEPT_CODE IS NOT NULL
GROUP BY DEPT_CODE;

HAVING절이란?
➡️ 그룹 함수로 값을 구해올 그룹에 대해 조건을 설정할 때 HAVING절을 이용할 수 있다. 그룹함수를 조건으로 사용
-- SELECT
-- FROM
-- [WHERE 조건식]
-- GROUP BY절
-- [HAVING 조건식]
🔥 예제) 평균 급여가 300만원 이상인 부서 조회

SELECT DEPT_CODE, AVG(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE
HAVING AVG(SALARY)>=3000000;

🔥 예제) 매니저가 관리하는 사원이 2명 이상인 매니저 아이디 조회
➡️ WHERE절을 이용하여 매니저가 존재하지 않는 사원의 결과를 제외
➡️ MANAGER_ID를 기준으로 그룹화 한다.
➡️ 그룹함수 COUNT() 를 이용하여 같은 MANAGER_ID의 수를 조건으로 하여 2명이상이면 출력
SELECT MANAGER_ID, COUNT(*)
FROM EMPLOYEE
WHERE MANAGER_ID IS NOT NULL
GROUP BY MANAGER_ID
HAVING COUNT(*)>=2;

🔥 예제) 남자, 여자 사원의 평균 급여를 구하고, 인원수 출력
➡️ SUBSTR() 함수를 이용하여 특정 결과값에 따른 그룹화가 가능하다.
SELECT
CASE
WHEN SUBSTR(EMP_NO,8,1) IN ('1','3') THEN '남'
WHEN SUBSTR(EMP_NO,8,1) IN ('2','4') THEN '여'
END AS 성별,
COUNT(*),
TO_CHAR(AVG(SALARY),'L999,999,999') AS 평균급여
FROM EMPLOYEE
GROUP BY SUBSTR(EMP_NO,8,1);

🔥 예제) 1900년대, 2000년대 입사한 사원 수 조회하기
SELECT DECODE(SUBSTR(EXTRACT(YEAR FROM HIRE_DATE),1,2), '19', '1900년대', '20', '2000년대') AS "입사구분 (1900/2000년대)", COUNT(*) AS 사원수
FROM EMPLOYEE
GROUP BY SUBSTR(EXTRACT(YEAR FROM HIRE_DATE),1,2);
