[MS SQL Server] #8_집계함수, GROUP BY, HAVING
안녕하세요. 문범우입니다.
이번 포스팅에서는 SUM, AVG, MIN, MAX와 같은 집계함수들에 대해서 알아보면서 GROUP BY절과 HAVING절에 대해서 다뤄보도록 하겠습니다.
1. 집계함수
집계함수는 값에 대해서 특정 연산을 수행하는 함수들을 이야기합니다.
합계를 구하는 SUM함수나 평균을 구하는 AVG함수, 개수를 세는 COUNT함수 등이 대표적입니다.
그럼 아래와 같이 이전 포스팅에서 사용했던 SampleDB를 사용하여 몇가지 집계함수에 대해서 함께 알아보도록 하겠습니다.
- SUM
SUM함수는 말 그대로 합계를 구하는 함수 입니다.
employee 테이블에서 연봉의 합계를 구하고자 할 때와 같은 경우에 아래와 같이 사용할 수 있습니다.
SELECT SUM(salary) FROM employee;
그럼 이번에는 employee 테이블에서 commission의 합계를 구해볼까요?
하지만 commission에는 NULL값이 포함되어 있습니다. 이전에는 NULL에 대한 연산을 진행할 때 그 결과가 NULL이 나오게 되어서 ISNULL이라는 함수를 이용했습니다.
그럼 집계함수에서는 어떨지 한번 확인해볼까요?
SELECT SUM(commission) FROM employee;
위의 결과에서 볼 수 있듯이 집계함수에서의 NULL은 무시가 됩니다.
- AVG
이어서 AVG함수에 대해서 알아봅시다.
AVG함수는 평균을 구하는 함수입니다. 그럼 월급의 평균은 어떠한지 확인해보도록 하겠습니다.
SELECT AVG(salary) FROM employee;
AVG함수 또한 NULL값이 존재할 때에는 NULL값은 무시하고 평균을 구하게 됩니다.
- MIN, MAX
MIN과 MAX는 최대값과 최소값을 구하는 함수 입니다.
다음과 같이 월급의 최소값과 최대값을 구해보도록 하겠습니다.
SELECT MIN(salary), MAX(salary) FROM employee;
- COUNT
마지막으로 알아볼 COUNT 함수는 개수를 세는 함수입니다.
이때 COUNT 또한 NULL값은 무시하게 됩니다. 즉, 값이 존재하는 데이터에 대한 개수만 세는 것이죠.
따라서 salary의 COUNT값과 commission의 COUNT값은 서로 다릅니다.
SELECT COUNT(salary), COUNT(commission) FROM employee;
2. GROUP BY
그런데 만약, 직급별 월급 평균, 월급 합계 등 특정 그룹별로 집계함수를 사용하고 싶을때는 어떻게 할까요?
테이블에서 특정 그룹을 만들 수 있도록 하는 것이 바로 GROUP BY 절 입니다.
즉, GROUP BY 'A' 라고 한다면 A칼럼에서 같은 것끼리 묶어서 하나의 GROUP를 만드는 것이죠.
그럼 바로 GROUP BY를 활용해보도록 하겠습니다.
위에서 이야기한 바와 같이 직급별 월급 평균은 다음과 같이 구할 수 있습니다.
SELECT job 직급, AVG(salary) 월급평균
FROM employee GROUP BY job;
위와 같이 직급별로 GROUP이 되어 AVG함수의 값이 나오는 것을 볼 수 있습니다.
하지만 우리가 다음과 같이 SELECT 문을 구성한다면 어떻게 될까요?
SELECT empName 이름, job 직급, AVG(salary) 월급평균
FROM employee GROUP BY job;
위의 구문을 실행시키면 아래와 같이 오류가 발생하게 됩니다.
오류메세지를 읽으며 한번 왜 오류가 발생하는지 생각해봅시다.
우리가 출력하고자 하는 empName 값이 집계함수에도 없고, GROUP BY 절에도 없어서 사용할 수 없다고 하네요.
그럼 empName이 집계함수나 GROUP BY 절에 있어야 한다는 의미인데, 왜 그럴까요?
우리가 결과를 출력하는 입장이라고 한번 생각해봅시다.
empName이 없을 때는 이전의 결과와 같이 직급과 월급평균을 잘 출력할 수 있었습니다.
예를 들어 과장의 월급평균은 483이란 결과를 가져왔죠.
그런데 이때 해당 레코드(행)에 empName을 출력해야 한다면, 어떠한 empName을 출력해야 할까요?
즉, 과장 직급의 483의 평균월급이라는 레코드는 '과장'이라는 값으로 여러개의 레코드가 그룹이 되어 있는 레코드 입니다. 즉 해당 레코드에는 여러개의 empName이 존재하는 것이죠.
따라서 SQL에서는 그 여러개 중에서 하나를 출력할 수 없기에 오류가 발생하는 것입니다.
만약 empName이 집계함수를 적용시키면 집계함수에 따른 값이 나오겠죠, 물론 문자열 값이기에 또 다른 오류가 발생하겠지만..
또한 empName을 GROUP BY절에 다시 써주면 아래와 같이 job과 empName이 동일한 레코드끼리 묶여서 나오기 때문에 사실상 현재 데이터에서는 모든 데이터를 출력하는 것과 같게 됩니다.
SELECT empName 이름, job 직급, AVG(salary) 월급평균
FROM employee GROUP BY job, empName;
3. HAVING
이번 포스팅에서 마지막으로 알아볼 것은 HAVING절 입니다.
HAVING은 간단하게 말해서, 우리가 위에서 배운 GROUP BY절을 통해 만들어진 GROUP에 대해서 조건을 거는 것 입니다.
그런데 우리는 이전에 조건을 거는 WHERE절에 대해서 학습하였습니다.
WHERE절과 HAVING절의 차이는 무엇일까요?
기본적으로 WHERE절은 모든 레코드(행)에 대해서 조건을 적용하게 됩니다.
하지만 HAVING절은 GROUP BY절을 통해 만들어진 GROUP 들에만 조건을 적용하는 것이죠.
이를 잘 이해하지 못하면 추후에 HAVING과 WHERE 사용에 있어 헷갈릴 수 있습니다.
그럼 바로 사용해보도록 하겠습니다.
각 직급에 대해 3명 이상인 직급과 그 인원수를 출력해보도록 하겠습니다.
SELECT job 직급, COUNT(job) '직급 수' FROM employee
GROUP BY job HAVING COUNT(job) >= 3;
위와 같이 사용됩니다.
그럼 만약,
"월급이 300만원 이상인 사람들에 대해서 직급별로 2명이상인 직급과 그 직급의 월급 평균을 구해라."
라면 어떻게 해야 할까요?
위와 같은 경우에 바로 WHERE절과 HAVING절이 같이 사용하게 됩니다.
SELECT job 직급, AVG(salary) 월급평균 FROM employee
WHERE salary >= 300
GROUP BY job HAVING COUNT(job) >= 2;
추후에 더 많은 데이터들을 대상으로 복잡한 쿼리문을 다루게 되면 충분히 헷갈릴 수 있는 점들이니 꼭 스스로 쿼리문을 작성해보면서 이해하기를 바랍니다.
이렇게 해서 집계함수와 GROUP BY, HAVING 절에 대해서 알아보았습니다.
궁금하거나 잘못된 점은 언제든 댓글이나 이메일, 카카오톡을 통해서 문의주시면 감사하겠습니다.