집계 함수는 여러 행의 데이터를 한 번에 처리해서 결과를 하나만 반환하는 함수들이야. PostgreSQL에서 자주 쓰는 집계 함수는 다음과 같아:
SUM()— 데이터 합계 구하기.AVG()— 평균값 구하기.MIN()— 최소값 찾기.MAX()— 최대값 찾기.COUNT()— 행 개수 세기.
처음 보면 되게 쉬워 보여. 함수에 컬럼이나 식을 넘기면 결과가 나오니까. 근데 만약 컬럼에 NULL이 있으면 어떻게 될까?
집계에서 NULL의 동작: 짧게 정리
여기서부터가 진짜 재밌는 부분이야:
SUM()이랑AVG()는NULL을 무시해. 만약 어떤 행에NULL이 있으면, 그 행은 계산에서 그냥 빠져. 합계가 늘어나려면 누가 "파티에 와야" 하잖아? 평균도 마찬가지로, 값이 하나 빠지면 평균을 낼 수 없으니까.MIN()이랑MAX()도NULL을 건너뛰어. 최소값이나 최대값을 구할 때NULL이 아닌 값들만 비교해. 예를 들어, 생일을 안 적은 가장 어린 직원을 찾을 때,NULL은 결과에 안 들어가.COUNT(*)는 모든 행을 세,NULL이 있어도. 근데COUNT(column)은 해당 컬럼에 값이 있는 행만 세니까NULL은 무시돼.
이제 예시로 더 자세히 볼게.
NULL이 있는 집계 함수 사용 예시
여기 students_scores라는 테이블이 있어. 학생들의 시험 점수를 담고 있어:
| student_id | name | score |
|---|---|---|
| 1 | 알리사 | 85 |
| 2 | 밥 | NULL |
| 3 | 찰리 | 92 |
| 4 | 다나 | NULL |
| 5 | 엘레나 | 74 |
이제 몇 가지 쿼리를 실행해서 결과를 볼게:
- 모든 점수의 합계:
SUM()
SELECT SUM(score) AS total_score
FROM students_scores;
결과:
| total_score |
|---|
| 251 |
보다시피, NULL 값들은 합계에서 그냥 빠졌어. 알리사(85), 찰리(92), 엘레나(74)만 더해서 251이야. 밥이랑 다나는 제외됐지.
- 평균 점수:
AVG()
SELECT AVG(score) AS average_score
FROM students_scores;
결과:
| average_score |
|---|
| 83.67 |
여기도 NULL은 무시됐고, 점수가 있는 학생만 평균을 냈어: (85 + 92 + 74) / 3 = 83.67.
- 최소/최대 점수:
MIN()과MAX()
SELECT
MIN(score) AS min_score,
MAX(score) AS max_score
FROM students_scores;
결과:
| min_score | max_score |
|---|---|
| 74 | 92 |
여기도 마찬가지로 NULL은 무시되고, 최소는 74, 최대는 92야.
- 행 개수 세기:
COUNT(*)vsCOUNT(column)
SELECT
COUNT(*) AS total_rows,
COUNT(score) AS non_null_scores
FROM students_scores;
결과:
| total_rows | non_null_scores |
|---|---|
| 5 | 3 |
COUNT(*)는score가NULL이어도 모든 행을 세.COUNT(score)는score에 값이 있는 행만 세.
실전 케이스
실제 상황 예시도 몇 개 볼게.
예시 1: 급여가 입력된 직원과 안 된 직원 세기
예를 들어, employees 테이블에 직원 급여가 있어.
| id | name | salary |
|---|---|---|
| 1 | Alex Lin | 50000 |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | 60000 |
| 4 | Otto Art | NULL |
| 5 | Liam Park | 55000 |
몇 명이 급여를 입력했고, 몇 명이 안 했는지 알고 싶어.
SELECT
COUNT(*) AS total_employees,
COUNT(salary) AS employees_with_salary,
COUNT(*) - COUNT(salary) AS employees_without_salary
FROM employees;
여기서:
COUNT(*)는 전체 직원 수를 반환해.COUNT(salary)는 급여가 입력된 직원 수를 세.- 급여가 없는 직원 수는 그냥 둘의 차이야.
결과
| total_employees | employees_with_salary | employees_without_salary |
|---|---|---|
| 5 | 3 | 2 |
예시 2: 누락된 데이터가 있는 상품 평균 가격 계산
네가 마법 상점 주인이라고 해보자. products 테이블에 price 컬럼이 있는데, 어떤 상품은 아직 가격이 없어.
| id | name | price |
|---|---|---|
| 1 | Magic Wand | 150 |
| 2 | Enchanted Cloak | NULL |
| 3 | Potion Bottle | 75 |
| 4 | Spell Book | 200 |
| 5 | Crystal Ball | NULL |
가격이 입력된 상품만 평균을 내고 싶어.
SELECT AVG(price) AS average_price
FROM products;
결과:
| average_price |
|---|
| 141.6667 |
만약 가격이 없는 상품에 기본값(예: 0)을 넣고 싶으면, 다음 강의에서 다룰 COALESCE() 함수를 쓰면 돼.
예시 3: 학생들 중 최소/최대 나이 찾기
students 테이블에 학생 나이가 저장돼 있는데, 어떤 학생은 나이가 NULL이야.
| id | name | age |
|---|---|---|
| 1 | Alex Lin | 20 |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | 19 |
| 4 | Otto Art | 22 |
| 5 | Liam Park | NULL |
가장 어린 학생과 가장 나이 많은 학생을 알고 싶어.
SELECT
MIN(age) AS youngest_student,
MAX(age) AS eldest_student
FROM students;
결과:
| youngest_student | eldest_student |
|---|---|
| 19 | 22 |
이 쿼리는 나이가 입력된 학생만 최소/최대 나이를 반환해. NULL은 또 무시돼.
특징과 주의할 점
NULL이 집계 함수에서 어떻게 동작하는지 쓸 때, 다음을 꼭 기억해:
SUM()이랑AVG()에서NULL은 계산에 포함되지 않아. "빈" 값을 계산에 넣고 싶지 않을 때 유용해.- 컬럼에
NULL이 있어도 행을 다 세고 싶으면COUNT(*)를 써. MIN()이나MAX()도NULL은 결과에 영향 없어. 근데 컬럼 전체가NULL이면 결과도NULL이야.
NULL 다룰 때 꿀팁
- 상황에 맞게 처리하자. 쿼리에서
NULL을 고려해야 하는지 항상 생각해.AVG()처럼 무시하는 게 맞을 때도 있고, 전체 개수를 셀 때는NULL도 포함해야 할 때가 있어. - 필요하면
COALESCE()를 써. 계산에서NULL을 기본값으로 바꾸고 싶으면COALESCE()가 친구가 될 거야(이건 다음 강의에서 더 자세히 배울 거야). COUNT(*)와COUNT(column)을 헷갈리지 말자. 이거 초보들이 자주 하는 실수야.COUNT(*)는 모든 행,COUNT(column)은 값이 있는 행만 세.
이제 NULL이 집계 함수에서 어떻게 "조용히" 영향을 주는지 알았지? 이걸 알면 쿼리에서 예상치 못한 결과를 피할 수 있고, NULL을 네 이득으로 쓸 수 있어. 다음 강의에서는 COALESCE()라는 강력한 도구로 NULL을 더 잘 다루는 법을 배울 거야.
GO TO FULL VERSION