본문 바로가기

SQL/기본 개념

GROUP BY / HAVING

▶ SELECT문 해석 순서

5번째 : SELECT 컬럼명 AS 별칭, 계산식, 함수식 < 조회할 컬럼명 >

1번째 : FROM 참조할 테이블명  < 어디에서 참조할 것인가 >

2번째 : WHERE 컬럼명 | 함수식 비교연산자 비교값  < 개별 컬럼 조건 확인 >

3번째 : GROUP BY 그룹을 묶을 컬럼명 < 비교할 그룹함수의 기준이 되는 컬럼 >

4번째 : HAVING 그룹함수식 비교연산자 비교값 < 그룹함수 조건 확인 >

6번째 : ORDER BY 컬럼명 | 별칭 | 컬럼순번 정렬방식 [ NULL FISRT | LAST] < 컬럼순번 정렬 >

▶ GROUP BY절

  • GROUP BY절 : 같은 값들이 여러 개 기록된 컬럼을 가지고, 같은 값들을 하나의 그룹으로 묶음
  • GROUP BY 컬럼명 | 함수식, ...
  • 여러 개의 값을 묶어서 하나로 처리할 목적으로 사용함
  • 그룹으로 묶은 값에 대해서 SELECT절에서 그룹함수를 사용함
  • 그룹 함수는 단 한 개의 결과값만 산출하기 때문에, 그룹이 여러 개일 경우 오류가 발생
    EX) SUM(SALARY) 가능 / SUM(SALARY, BONUS) 오류 발생
  • 여러 개의 결과값을 산출하기 위해 그룹 함수가 적용된 그룹의 적용된 기준을 GROUP BY절에 기술
-- EX) EMP 테이블에서 부서코드, 부서(그룹)별 급여 합계 조회
SELECT DEPT_CODE, SUM(SALARY) FROM EMPLOYEE;

※ 오류 발생 : 단일 그룹의 그룹 함수가 아님. 해당 문제에서 DEPT_CODE 컬럼은 23행 / SUM(SALARY) 컬럼은 1행
    → 하나의 표에 작성 불가

SELECT DEPT_CODE, SUM(SALARY)
FROM EMPLOYEE
GROUP BY DEPT_CODE;

※ 부서별로 그룹을 지어 각 그룹의 합계 조회 → 기준점이 되는 것 : 부서(부서 코드로 확인 가능)

-- EX) EMP 테이블에서 성별과 성별별 (1)급여 평균(정수처리), (2)급여 합계, (3)인원 수를 조회하고,
-- 인원수로 내림차순 정렬하기
SELECT DECODE(SUBSTR(EMP_NO,8,1),1,'남',2,'여') 성별, FLOOR(AVG(SALARY)) 급여평균, SUM(SALARY) 급여합계, COUNT(*) 인원수
FROM EMPLOYEE
GROUP BY DECODE(SUBSTR(EMP_NO,8,1),1,'남',2,'여');

※ 급여 평균, 급여 합계, 인원 수의 기준이 되는 항목 : 성별 (같은 값들이 여러 개 기록된 컬럼 중 하나)
    → GROUP BY절에서 사용 가능함
※ DECODE 작성시 주의! : DEC0DE( 계산식 | 컬럼명, 조건값1,선택값1,조건값2,선택값2,...,아무 것도 일치하지 않을 때)

  • WHERE절과 GROUP BY절 혼합하여 사용
  • WHERE절은 개별 컬럼 값에 대한 조건! (★★★ SELECT문 해석 순서 꼭 기억해야함 ★★★)
-- EX) EMP 테이블에서 부서코드가 'D5','D6'인 부서의 평균 급여 조회
SELECT DEPT_CODE, FLOOR(AVG(SALARY)) FROM EMPLOYEE WHERE DEPT_CODE IN ('D5','D6')
GROUP BY DEPT_CODE;

※ 4번째 : SELECT 컬럼명 AS 별칭, 계산식, 함수식 < 조회할 컬럼명 >
    1번째 : FROM 참조할 테이블명  < 어디에서 참조할 것인가 >
    2번째 : WHERE 컬럼명 | 함수식 비교연산자 비교값  < 개별 컬럼 조건 확인 >
    3번째 : GROUP BY 그룹을 묶을 컬럼명 < 비교할 그룹함수의 기준이 되는 컬럼 >

  • 여러 컬럼을 묶어서 그룹으로 지정 가능 → 그룹 내 그룹이 가능함
  • ★★★ GROUP BY 사용 시 주의사항 ★★★
  • SELECT문에 GROUP BY절을 사용할 경우,
    SELECT절에 명시한 조회하려는 컬럼 중
    그룹함수가 적용되지 않은 컬럼은 모두 GROUP BY절에 작성해야 함
-- EX) EMP 테이블에서 부서별로 같은 직급인 사원의 급여 합계를 조회하고 
-- 부서코드 오름차순으로 정렬하기
SELECT DEPT_CODE, JOB_CODE, SUM(SALARY) FROM EMPLOYEE
GROUP BY DEPT_CODE, JOB_CODE
ORDER BY DEPT_CODE;

※ SELECT문에 GROUP BY절 사용할 때, SELECT절에 명시된 조회하려는 컬럼 중
    DEPT_CODE(부서코드), JOB_CODE(직급코드)는 그룹함수 적용 X
    → GROUP BY절에 작성해야 함!

▶ HAVING절

  • HAVING절 : 그룹함수로 구해올 그룹에 대한 조건을 설정할 때 사용
  • HAVING 컬럼명 | 함수식 비교연산자 비교값
-- EX) 부서별 평균 급여가 300만원 이상인 부서를 조회하여 부서코드 오름차순으로 정렬하기
SELECT DEPT_CODE, FLOOR(AVG(SALARY)) FROM EMPLOYEE
GROUP BY DEPT_CODE
HAVING FLOOR(AVG(SALARY))>=3000000
ORDER BY DEPT_CODE;

만약 HAVING절 대신 WHERE절 들어갈 경우, 급여가 300만원 이상인 직원의 부서별 급여 평균이 구해짐

SELECT DEPT_CODE, FLOOR(AVG(SALARY))
FROM EMPLOYEE
WHERE SALARY>=3000000
GROUP BY DEPT_CODE
ORDER BY DEPT_CODE;

-- EX) EMP 테이블에서 부서별 70년대생의 급여 평균이 300만원 이상인 부서를 조회하여 
-- 부서코드 내림차순 정렬하기
SELECT DEPT_CODE, FLOOR(AVG(SALARY)) FROM EMPLOYEE
-- 개별 컬럼의 조건 확인(70년대생)
WHERE SUBSTR(EMP_NO,1,2)>=70 AND SUBSTR(EMP_NO,1,2)<80
GROUP BY DEPT_CODE
-- 그룹 함수의 조건 확인(급여 평균)
HAVING FLOOR(AVG(SALARY))>=3000000
ORDER BY DEPT_CODE DESC;

▶ 집계함수(ROLLUP, CUBE)

  • 집계함수 : 그룹별 산출한 결과값의 집계를 계산하는 함수 / GROUP BY절에만 작성하는 함수
  • ROLLUP 함수 : 그룹별로 중간 집계 처리를 하는 함수
    그룹별로 묶여진 값에 대한 '중간 집계'와 '총 집계'를 계산하여 자동으로 추가하는 함수
    * 인자로 전달받은 그룹 중에서 가장 먼저 지정한 그룹별 합계와 총 합계를 구하는 함수
-- EX) EMP 테이블에서 각 부서에 소속된 직급별 급여 합계, 부서별 급여 합계, 전체 직원 급여 총합 조회하기
SELECT DEPT_CODE, JOB_CODE, SUM(SALARY) FROM EMPLOYEE
GROUP BY ROLLUP(DEPT_CODE, JOB_CODE)
ORDER BY DEPT_CODE;

  • CUBE 함수 : 그룹별 산출한 결과를 집계하는 함수
    ★★ 그룹으로 지정된 모든 그룹에 대한 집계와 총 합계를 구하는 함수
-- EX) EMP 테이블에서 각 부서마다 직급별 급여 합계, 부서 전체 급여 합계, 전체 직원 급여 총합 조회하기
SELECT DEPT_CODE, JOB_CODE, SUM(SALARY) FROM EMPLOYEE
GROUP BY CUBE(DEPT_CODE, JOB_CODE)
ORDER BY DEPT_CODE;

-- ROLLUP 결과에 아래 SQL문 결과가 추가된 것과 동일함
SELECT JOB_CODE, SUM(SALARY)
FROM EMPLOYEE
GROUP BY JOB_CODE
ORDER BY JOB_CODE

  • SET OPERATION (집합 연산) : 여러 개의 SELECT 결과물을 하나의 쿼리로 만드는 연산자
  • 여러가지의 조건이 있을 때, 그에 해당하는 여러 개의 결과값을 결합시키고 싶을 때 사용
  • 초보자들이 사용하기 쉬움
  • (주의) 집합 연산에 사용되는 SELECT문은 SELECT절이 동일해야만 함
  • UNION : OR와 같은 개념 (합집합) → 중복 제거
  • INTERSECT : AND와 같은 개념 (교집합)
  • UNION ALL : OR 결과값에 AND 결과값이 더해진 것(합집합 + 교집합) → 중복 미제거
  • MINUS : 차집합 개념

1) UNION : 여러 개의 쿼리 결과를 하나로 합치는 연산자 / 중복된 영역을 제외하여 하나로 합침

-- EX) 부서코드가 'D5'인 사원의 사번, 이름, 부서코드, 급여 조회
-- + 급여가 300만 초과인 사원의 사번, 이름, 부서코드, 급여 조회
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은 OR 연산의 결과와 같음
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5' OR SALARY > 3000000;

2) INTERSECT는 AND와 같은 개념 (교집합)

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;

  • INTERSECT는 AND 연산의 결과와 같음
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5' AND SALARY > 3000000;

3) 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;

UNION ALL에서는 중복값 포함

4) 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

선행 SELECT 결과에서 다음 SELECT 결과와 겹치는 부분 제외한 값

  • MINUS는 AND 연산 + 비교 연산을 반대로 작성하면 됨
SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D5'
AND SALARY <= 3000000;

5) 그 외 : 여러 SELECT 집합 연산이 가능함

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 DEPT_CODE = 'D6'

UNION

SELECT EMP_ID, EMP_NAME, DEPT_CODE, SALARY
FROM EMPLOYEE
WHERE DEPT_CODE = 'D9';

'SQL > 기본 개념' 카테고리의 다른 글

SUBQUERY(서브쿼리)  (0) 2024.12.16
JOIN  (0) 2024.12.16
그룹(GROUP) 함수  (0) 2024.12.16
함수  (0) 2024.12.16
SELECT (DML / DQL)  (2) 2024.12.16