Database

SQL - NULL 총정리

guwon2 2025. 10. 19. 16:19

SQL에서 NULL 값 처리 정리


NULL의 기본 개념

NULL은 "값이 없음" 또는 "알 수 없는 값"을 나타내는 특별한 상태이다. 중요한 점은 NULL은 0도 아니고 빈 문자열('')도 아니라는 것.

  • 0: 숫자 0이라는 명확한 값
  • 빈 문자열(''): 길이가 0인 문자열이라는 명확한 값
  • NULL: 값 자체가 존재하지 않는 상태

NULL과 비교 연산

SQL에서 NULL은 삼중 논리(Three-Valued Logic)를 따른다. 일반적인 프로그래밍 언어의 TRUE/FALSE와 달리, SQL은 TRUE, FALSE, UNKNOWN 세 가지 값을 가진다.

-- 잘못된 비교
SELECT * FROM users WHERE email = NULL;      -- 결과 없음
SELECT * FROM users WHERE email != NULL;     -- 결과 없음

-- 올바른 비교
SELECT * FROM users WHERE email IS NULL;     -- NULL인 행 반환
SELECT * FROM users WHERE email IS NOT NULL; -- NULL이 아닌 행 반환

NULL과의 모든 비교 연산은 UNKNOWN을 반환합니다. 이는 WHERE 절에서 조건이 TRUE인 행만 선택하기 때문에, NULL 비교 시 IS NULL 또는 IS NOT NULL을 사용해야 한다.

-- NULL과의 비교 연산 결과
NULL = 10       -- UNKNOWN
NULL != 10      -- UNKNOWN
NULL > 10       -- UNKNOWN
NULL AND TRUE   -- UNKNOWN
NULL OR FALSE   -- UNKNOWN

GROUP BY와 NULL

NULL은 하나의 그룹으로 묶인다

GROUP BY 절에서 NULL 값이 있는 컬럼을 기준으로 그룹화하면, 모든 NULL 값들이 하나의 그룹으로 묶인다.

예제 데이터

id region sales_amount
1 East 100
2 West 150
3 NULL 200
4 East 250
5 NULL 300

쿼리 및 결과

SELECT region, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY region;

결과:

region total_sales
East 350
West 150
NULL 500

NULL 값을 가진 행(id=3, id=5)이 하나의 그룹으로 묶여서 합계 500이 계산된다.

NULL 그룹 제외하기

NULL 그룹을 제외하고 싶다면 WHERE 절이나 HAVING 절을 사용하면 된다.

-- WHERE 절로 NULL 제외 (그룹화 전에 제외)
SELECT region, SUM(sales_amount) AS total_sales
FROM sales
WHERE region IS NOT NULL
GROUP BY region;

-- HAVING 절로 NULL 제외 (그룹화 후에 제외)
SELECT region, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY region
HAVING region IS NOT NULL;

NULL을 다른 값으로 변환하기

NULL을 특정 값으로 변환하여 그룹화할 수도 있다.

-- COALESCE 사용
SELECT COALESCE(region, 'Unknown') AS region, 
       SUM(sales_amount) AS total_sales
FROM sales
GROUP BY COALESCE(region, 'Unknown');

-- MySQL: IFNULL
SELECT IFNULL(region, 'Unknown') AS region, 
       SUM(sales_amount) AS total_sales
FROM sales
GROUP BY IFNULL(region, 'Unknown');

-- Oracle: NVL
SELECT NVL(region, 'Unknown') AS region, 
       SUM(sales_amount) AS total_sales
FROM sales
GROUP BY NVL(region, 'Unknown');

집계함수와 NULL 처리

모든 집계함수는 기본적으로 NULL 값을 무시한다. 단, COUNT(*)는 예외

COUNT 함수

COUNT 함수는 사용 방식에 따라 NULL 처리가 다르다.

COUNT(*) vs COUNT(column)

-- 예제 데이터
-- id | name  | score
-- 1  | Alice | 90
-- 2  | Bob   | 80
-- 3  | Carol | NULL
-- 4  | Dave  | 70

-- COUNT(*): 전체 행 개수 (NULL 포함)
SELECT COUNT(*) FROM students;
-- 결과: 4

-- COUNT(column): NULL이 아닌 값의 개수
SELECT COUNT(score) FROM students;
-- 결과: 3

-- COUNT(1): COUNT(*)와 동일 (NULL 포함)
SELECT COUNT(1) FROM students;
-- 결과: 4

정리:

  • COUNT(*): 모든 행을 세며, NULL 포함
  • COUNT(column): 해당 컬럼에서 NULL이 아닌 값만 셈
  • COUNT(1): COUNT(*)와 동일하게 동작 (성능도 동일)

SUM 함수

SUM 함수는 NULL 값을 무시하고 나머지 숫자만 합산한다.

-- 예제 데이터
-- id | amount
-- 1  | 100
-- 2  | 200
-- 3  | NULL
-- 4  | 300

SELECT SUM(amount) FROM orders;
-- 결과: 600 (100 + 200 + 300)
-- NULL은 무시됨, 0으로 계산되지 않음

중요: NULL + 숫자 = NULL이지만, SUM 함수는 내부적으로 NULL을 제외하고 계산한다.

-- 직접 연산 vs SUM 함수
SELECT 100 + 200 + NULL + 300;  -- 결과: NULL
SELECT SUM(amount) FROM orders; -- 결과: 600

AVG 함수

AVG 함수는 NULL을 제외한 값들의 평균을 계산한다. 이 부분에서 주의가 필요하다.

-- 예제 데이터
-- id | score
-- 1  | 10
-- 2  | 20
-- 3  | 30
-- 4  | NULL

-- AVG 함수: NULL 제외
SELECT AVG(score) FROM students;
-- 결과: 20 = (10 + 20 + 30) / 3

-- NULL을 0으로 처리하고 싶다면
SELECT AVG(IFNULL(score, 0)) FROM students;  -- MySQL
-- 결과: 15 = (10 + 20 + 30 + 0) / 4

-- 또는 직접 계산
SELECT SUM(score) / COUNT(*) FROM students;
-- 결과: 15 = 60 / 4

정리:

  • AVG(column): NULL을 제외하고 평균 계산 = SUM(column) / COUNT(column)
  • AVG(IFNULL(column, 0)): NULL을 0으로 치환하여 평균 = SUM(column) / COUNT(*)

MIN / MAX 함수

MIN과 MAX 함수는 NULL을 무시하고 최소값/최대값을 반환한다.

-- 예제 데이터
-- id | price
-- 1  | 100
-- 2  | NULL
-- 3  | 300
-- 4  | 200

SELECT MIN(price), MAX(price) FROM products;
-- 결과: MIN = 100, MAX = 300
-- NULL은 무시됨