모던지 / SQL 개발자 / SQL 기본 및 활용 4강. 집계 함수와 GROUP BY

SQL 기본 및 활용 4강. 집계 함수와 GROUP BY

WHERE는 행을 걸러 내고 HAVING은 묶음을 걸러 냅니다. 둘을 바꿔 쓰면 결과가 아니라 의미가 달라집니다.

풀고 시작

문제 1. 부서별 평균 급여가 300을 넘는 부서만 뽑으려 합니다. 조건을 어디에 써야 할까요?
평균은 묶은 뒤에야 계산되므로 묶음을 걸러 내는 HAVING에 써야 합니다. WHERE는 묶기 전 개별 행을 걸러 내는 절이라 아직 존재하지 않는 평균을 참조할 수 없습니다.

여러 행을 하나로 줄이는 함수

집계 함수(aggregate function)는 여러 행을 입력으로 받아 결과 한 건을 돌려줍니다. 3강의 단일행 함수와 정반대죠. 대표적인 다섯 가지는 COUNT, SUM, AVG, MAX, MIN입니다.

여기서 가장 자주 틀리는 지점은 NULL 처리입니다. 집계 함수는 값이 없는 행을 계산에서 제외합니다. 0으로 보고 더하는 것이 아니라 아예 없는 것으로 취급하죠. 그래서 평균을 낼 때 분모가 전체 행 수가 아니라 값이 있는 행 수가 됩니다. 값이 없는 행을 0으로 세어야 하는 업무라면 3강의 NVL로 먼저 채워 넣은 뒤 평균을 내야 합니다.

COUNT는 세 가지 형태를 구분해야 합니다. 별표를 쓰면 전체 행 수를 세고, 컬럼을 지정하면 그 컬럼에 값이 있는 행 수를 세며, DISTINCT를 붙이면 서로 다른 값의 개수를 셉니다. 이 셋의 결과가 다르다는 사실이 곧 데이터에 NULL과 중복이 있다는 뜻입니다.

MAX와 MIN은 숫자만 받는 함수가 아닙니다. 문자에도, 날짜에도 씁니다. 가장 늦은 주문일을 찾는 것이 MAX죠. 반면 SUM과 AVG는 숫자에만 쓸 수 있습니다.

GROUP BY, 집합을 잘게 쪼개기

집계 함수만 쓰면 테이블 전체가 한 덩어리로 요약됩니다. 부서별로, 월별로 나눠 보고 싶으면 GROUP BY로 기준을 줍니다.

SELECT 부서코드, COUNT(*) AS 인원, AVG(급여) AS 평균급여
  FROM 사원
 GROUP BY 부서코드;

여기서 지켜야 하는 규칙이 하나 있고, 이것이 시험에서 가장 많이 나옵니다. GROUP BY를 쓰면 SELECT 절에는 GROUP BY에 적은 컬럼과 집계 함수만 올 수 있습니다. 부서별로 묶어 놓고 사원명을 함께 뽑으라고 하면, 한 부서에 사원이 여러 명이니 어느 이름을 내놓아야 할지 정할 수 없습니다. 그래서 오류가 납니다.

또 하나, GROUP BY 절에서는 SELECT 절의 별칭을 쓸 수 없습니다. 1강에서 본 처리 순서 때문입니다. GROUP BY가 SELECT보다 먼저 처리되니까요. 그리고 GROUP BY는 결과를 정렬해 주지 않습니다. 정렬이 필요하면 ORDER BY를 따로 써야 합니다. 일부 제품이 우연히 정렬된 결과를 내주더라도 보장된 동작이 아닙니다.

WHERE와 HAVING, 걸러 내는 대상이 다릅니다

둘 다 조건을 쓰는 절인데 왜 나뉘어 있을까요. 처리 순서를 놓고 보면 답이 바로 나옵니다.

처리 시점 걸러 내는 대상 집계 함수 사용
WHERE 묶기 전 개별 행 쓸 수 없습니다
HAVING 묶은 뒤 그룹 쓸 수 있습니다

그래서 "재직 중인 사원만 대상으로 부서별 평균 급여를 구하고, 그중 평균이 300을 넘는 부서만 보고 싶다"는 요구는 두 절을 모두 씁니다. 재직 여부는 개별 행의 성질이니 WHERE로, 평균 조건은 그룹의 성질이니 HAVING으로 갑니다.

성능 면에서도 차이가 있습니다. WHERE로 먼저 걸러 내면 묶어야 할 행 자체가 줄어듭니다. 같은 결과를 내는 조건이라면 WHERE에 쓸 수 있는 것을 HAVING으로 미루지 않는 편이 유리하죠.

한 가지 덧붙이면, HAVING은 GROUP BY 없이도 쓸 수 있습니다. 이때는 테이블 전체가 하나의 그룹이 되어 그 그룹에 조건이 걸립니다. 자주 쓰는 형태는 아니지만 문법상 가능합니다.

빈 결과와 집계 함수의 성질

집계 함수의 성질 중 실무에서 놀라게 되는 것이 하나 있습니다. 조건에 맞는 행이 하나도 없을 때 COUNT는 0을 돌려주지만 SUM은 NULL을 돌려줍니다.

이유는 앞에서 본 규칙 그대로입니다. COUNT는 개수를 세는 함수라 셀 것이 없으면 0이고, SUM은 값을 더하는 함수라 더할 값이 없으면 결과가 없는 것입니다. 이 결과를 그대로 다른 계산에 넣으면 3강에서 본 NULL 전파가 일어나 최종 금액이 통째로 비어 버립니다. 그래서 합계 결과를 화면에 내보낼 때는 NVL로 감싸 두는 것이 관례입니다.

GROUP BY로 묶었을 때 어느 그룹에도 속하지 않는 행은 없습니다. 다만 조건에 걸려 사라진 행은 그룹 자체를 만들지 않으므로, "주문이 없는 부서"처럼 0으로 보여야 하는 항목이 아예 목록에서 빠집니다. 6강과 7강에서 외부 조인을 배우면 이 문제를 해결하는 법이 나옵니다.

다음 강에서는 결과를 줄 세우는 ORDER BY를 봅니다. 짧지만 NULL의 위치와 정렬 기준 지정 방법에서 갈리는 문제가 꾸준히 나옵니다.

인출 문제

문제 1. 조건에 맞는 행이 한 건도 없을 때 COUNT와 SUM의 반환값을 순서대로 짝지은 것은?
셀 것이 없으면 개수는 0이지만, 더할 값이 없으면 합계는 존재하지 않으므로 NULL입니다. 합계를 그대로 다른 계산에 넣으면 결과 전체가 NULL이 되므로 대체값으로 감싸 두는 편이 안전합니다.
문제 2. GROUP BY 절을 사용한 SELECT 문에서 허용되지 않는 것은?
한 그룹에 여러 값이 들어 있으므로 그중 무엇을 내놓아야 하는지 정할 수 없어 오류가 납니다. 그룹 기준 컬럼과 집계 함수만 결과에 올 수 있습니다.
문제 3. WHERE 절과 HAVING 절에 대한 설명으로 옳은 것은?
개별 행 조건을 WHERE로 앞당기면 집계 대상 자체가 줄어듭니다. 집계 함수는 묶은 뒤에야 값이 생기므로 WHERE에 쓸 수 없고, HAVING은 GROUP BY 없이도 전체를 한 그룹으로 보아 쓸 수 있습니다.
문제 4. 어떤 컬럼에 값이 없는 행이 섞여 있을 때 COUNT를 별표로 쓴 결과와 그 컬럼을 지정한 결과의 관계는?
별표는 전체 행을 세고 컬럼 지정은 값이 있는 행만 셉니다. 값이 없는 행이 하나라도 있으면 후자가 작아지고, 없으면 같아집니다.

더 풀기

출제기준의 세세항목을 따라 이 강의 범위에서 새로 낸 문제입니다. 모의고사도 여기에서 뽑습니다.

묶음 1

문제 1. 집계 함수의 특징으로 가장 알맞은 것은?
집계 함수는 여러 행을 하나로 줄입니다. 행마다 결과를 내는 것은 단일행 함수이고, 행을 남기면서 집계하는 것은 윈도우 함수입니다.
문제 2. 집계 함수가 NULL을 다루는 방식으로 옳은 것은?
전체 행 수를 세는 경우를 빼면 집계 함수는 NULL을 빼고 계산합니다. 그래서 평균의 분모가 전체 행 수와 다를 수 있습니다.
문제 3. 다섯 행 가운데 두 행의 급여가 NULL이고 나머지 셋이 백과 이백과 삼백일 때 평균 급여는?
NULL을 뺀 세 행의 합 육백을 셋으로 나누어 이백입니다. 다섯으로 나눈 백이십이 아닙니다.
문제 4. 같은 데이터에서 NULL을 영으로 바꾼 뒤 평균을 구하면 결과는?
영으로 채우면 다섯 행 모두 계산에 들어가 육백을 다섯으로 나눈 백이십이 됩니다. 어느 쪽이 맞는지는 업무가 정합니다.
문제 5. 전체 행 수를 세는 방식과 특정 컬럼을 지정해 세는 방식의 차이로 옳은 것은?
별표는 행 자체를 세고 컬럼을 지정하면 그 컬럼에 값이 있는 행만 셉니다. 중복 제거는 DISTINCT를 넣어야 일어납니다.
문제 6. 최댓값과 최솟값을 구하는 함수를 문자 컬럼에 적용할 수 있나요?
문자에도 순서가 있으므로 최대와 최소를 구할 수 있습니다. 날짜에도 적용할 수 있어 가장 이른 날과 늦은 날을 찾을 때 씁니다.
문제 7. GROUP BY 절이 하는 일로 가장 알맞은 것은?
GROUP BY는 집합을 잘게 나눕니다. 정렬은 ORDER BY, 행을 거르는 것은 WHERE의 일입니다.
문제 8. GROUP BY를 쓴 질의의 SELECT 절에 올 수 있는 것으로 옳은 것은?
그룹 안에서 값이 하나로 정해지지 않는 컬럼은 무엇을 보여 줄지 알 수 없습니다. 그래서 기준 컬럼과 집계 결과만 허용됩니다.
문제 9. 부서별 사원 수를 구할 때 부서코드가 NULL인 사원들은 어떻게 처리되나요?
GROUP BY에서는 NULL을 같은 것으로 보아 하나의 그룹으로 묶습니다. 비교에서 같지 않다고 판정하는 것과는 다른 규칙입니다.
문제 10. 부서코드가 십, 십, 이십, NULL, NULL인 다섯 행을 부서코드로 묶으면 결과 행 수는?
십 그룹과 이십 그룹과 NULL 그룹으로 세 행이 됩니다.

묶음 2

문제 1. WHERE와 HAVING의 차이로 가장 정확한 것은?
처리 순서가 다릅니다. WHERE로 걸러진 행은 애초에 그룹에 들어가지 않고, HAVING은 이미 계산된 집계 결과를 봅니다.
문제 2. HAVING 절에서 집계 함수를 쓸 수 있는 이유는?
순서를 보면 이유가 분명합니다. WHERE 시점에는 아직 그룹이 없어 집계값이 존재하지 않습니다.
문제 3. 부서별 평균 급여가 삼백 이상인 부서만 보려면 어느 절에 조건을 써야 하나요?
평균은 그룹이 만들어진 뒤에 계산되므로 HAVING에 씁니다.
문제 4. 직급이 사원인 행만 대상으로 부서별 평균 급여를 구하려면 조건을 어디에 쓰는 편이 좋은가요?
그룹에 들어가기 전에 걸러야 대상 자체가 줄어듭니다. HAVING으로도 표현할 수 있는 경우가 있지만 불필요하게 많이 묶은 뒤 버리게 됩니다.
문제 5. WHERE로 쓸 수 있는 조건을 HAVING에 쓰면 생기는 문제로 가장 알맞은 것은?
결과는 같을 수 있지만 일하는 양이 다릅니다. 걸러 낼 수 있으면 최대한 앞에서 거르는 것이 원칙입니다.
문제 6. GROUP BY 없이 HAVING만 쓰면 어떻게 되나요?
그룹 기준이 없으면 테이블 전체가 하나의 그룹입니다. 그 그룹의 집계값에 조건을 걸 수 있습니다.
문제 7. 부서별 사원 수를 구했더니 어떤 부서가 결과에 아예 나타나지 않았습니다. 가장 가능성이 높은 이유는?
그룹은 존재하는 행에서만 만들어집니다. 사원이 없는 부서도 보이게 하려면 부서 테이블을 기준으로 외부 조인을 해야 합니다.
문제 8. 사원이 없는 부서를 포함해 부서별 사원 수를 구할 때 개수를 세는 대상으로 알맞은 것은?
외부 조인 결과에서 별표를 세면 짝이 없는 부서도 한 행이 있어 일이 나옵니다. 사원 쪽 컬럼을 세면 NULL이 제외되어 영이 나옵니다.
문제 9. 집계 함수 안에 DISTINCT를 넣으면 어떤 효과가 있나요?
서로 다른 값의 개수나 서로 다른 값의 합을 구할 때 씁니다. 결과 행 수는 그대로 하나입니다.
문제 10. 급여가 백, 백, 이백인 세 행에서 중복을 제거한 급여의 합은?
중복을 없애면 백과 이백이 남아 합이 삼백입니다.

묶음 3

문제 1. 부서별 급여 합계를 구했더니 어떤 부서의 합계가 NULL로 나왔습니다. 가장 가능성이 높은 이유는?
더할 값이 하나도 없으면 합계는 NULL입니다. 사원이 아예 없다면 그 그룹 자체가 만들어지지 않습니다.
문제 2. 부서별 사원 수와 부서별 급여가 있는 사원 수가 다르게 나온다면 그 이유로 가장 알맞은 것은?
별표는 행을 세고 컬럼 지정은 값이 있는 행만 셉니다. 이 차이가 곧 NULL의 개수입니다.
문제 3. 그룹으로 묶은 결과를 다시 그룹의 집계값으로 정렬하려면?
ORDER BY는 SELECT 이후에 처리되므로 집계 결과와 별칭을 모두 쓸 수 있습니다.
문제 4. GROUP BY 절에 SELECT에 없는 컬럼을 써도 되나요?
기준으로만 쓰고 화면에는 집계값만 보여 줄 수 있습니다. 다만 어떤 그룹의 값인지 알 수 없어져 실무에서는 함께 보여 주는 편입니다.
문제 5. 두 개의 컬럼으로 그룹을 묶으면 그룹의 개수는 어떻게 되나요?
데이터에 없는 조합은 그룹이 되지 않습니다. 모든 조합을 보고 싶다면 별도의 기준 집합과 외부 조인을 해야 합니다.
문제 6. 부서가 세 개이고 직급이 네 개인데 부서와 직급으로 묶은 결과가 일곱 행이라면?
열두 가지 조합이 모두 있어야 열두 행이 됩니다. 없는 조합은 애초에 행이 없습니다.
문제 7. 집계 함수를 중첩해서 쓰려 할 때 지켜야 할 점으로 가장 알맞은 것은?
부서별 평균 가운데 최댓값처럼 두 단계 집계가 필요할 때는 한 번 묶은 결과를 다시 대상으로 삼아야 합니다.
문제 8. 부서별 평균 급여 중 가장 큰 값을 구하는 가장 명확한 방법은?
두 단계 집계이므로 한 번 묶은 결과를 다시 대상으로 삼아야 합니다. 전체 평균이나 급여 최댓값과는 전혀 다른 값입니다.
문제 9. 집계 결과가 없는 그룹을 영으로 보이게 하려면 어떤 함수를 함께 쓰는 것이 좋은가요?
합계나 평균이 NULL로 나오는 자리를 영으로 보이고 싶다면 대체 함수를 감싸면 됩니다. 다만 값이 없는 것과 영인 것의 뜻이 다르다는 점은 기억해야 합니다.
문제 10. 다음 중 옳지 않은 설명은?
정렬은 보장되지 않습니다. 제품이나 실행 방식에 따라 정렬된 것처럼 보일 수 있지만 순서가 필요하면 반드시 명시해야 합니다.

이전: 3강 단일행 함수 · 다음: 5강 ORDER BY 절

모던지 · 궁금하면 모던지 GitHub · 2026-09-10