SQL에서 NULL과 빈 문자열 차이 | age_certification 필터링 실수 방지

SQL에서 결측처럼 보이는 값이 있다고 해서 전부 NULL인 것은 아니다. 실제 데이터에서는 NULL 대신 빈 문자열('') 로 들어간 경우가 생각보다 자주 나온다. 그래서 필터링 전에 값을 직접 확인하지 않으면, 분명 등급 없는 데이터를 제외했다고 생각했는데 결과가 이상하게 남아 있는 상황이 생긴다.

이 문제는 특히 범주형 컬럼을 다룰 때 자주 나온다. 예를 들어 콘텐츠 데이터의 age_certification처럼 연령 등급이 들어가는 컬럼은 값이 없을 때 NULL일 수도 있고, 빈 문자열일 수도 있고, 심지어 공백 문자열일 수도 있다. 그래서 분석 전에 먼저 해야 할 일은 **“결측처럼 보이는 값이 실제로 어떤 형태로 저장돼 있는지 확인하는 것”**이다.

NULL과 빈 문자열은 왜 다를까

SQL에서 NULL은 “값이 없음”을 의미한다.

반면 빈 문자열 ''은 길이가 0인 문자열 값이다. 즉 둘은 겉으로 보면 둘 다 비어 보일 수 있지만, SQL 입장에서는 완전히 다른 값이다.

이 차이 때문에 아래 두 조건은 같은 의미가 아니다.

WHERE age_certification IS NULL
WHERE age_certification = ''

첫 번째는 실제로 값이 비어 있는 경우만 찾고,

두 번째는 문자열 값은 존재하지만 그 내용이 비어 있는 경우만 찾는다.

즉, 데이터에 따라 둘 중 하나만 써서는 결측처럼 보이는 값을 다 잡지 못할 수 있다.

왜 이 문제가 자주 생기나

CSV, 수집 데이터, 외부 API, 수동 정제 과정을 거친 데이터는 결측 표현 방식이 제각각인 경우가 많다. 어떤 시스템은 값이 없으면 NULL로 저장하고, 어떤 시스템은 빈 문자열로 저장한다. 사용자는 둘 다 “비어 있음”으로 보지만, SQL은 그렇게 처리하지 않는다.

그래서 분석을 시작할 때 바로 필터를 쓰기보다, 먼저 아래 질문을 확인하는 게 안전하다.

  • 이 컬럼은 실제로 NULL이 들어가 있나
  • 아니면 빈 문자열이 들어가 있나
  • 둘 다 섞여 있나
  • 공백이 들어간 값은 없나

결측 처리 방식부터 먼저 보는 습관이 중요하다.

값 종류는 먼저 DISTINCT로 확인하는 게 좋다

가장 먼저 할 일은 이 컬럼에 어떤 값들이 들어 있는지 직접 보는 것이다.

SELECT DISTINCT age_certification
FROM titles;

이 쿼리는 age_certification에 어떤 값 종류가 있는지 보여준다.

이 단계에서 실제 데이터에

  • PG
  • R
  • TV-MA
  • NULL
  • ''

같은 값이 어떻게 섞여 있는지 감이 잡힌다.

즉 DISTINCT는 단순 조회가 아니라, 필터링 전략을 정하기 전에 상태를 점검하는 쿼리라고 보면 된다.

NULL 여부는 IS NULL로 확인한다

NULL은 등호(=)로 비교하지 않는다. NULL 확인은 반드시 IS NULL 또는 IS NOT NULL을 써야 한다.

SELECT *
FROM titles
WHERE age_certification IS NULL;

이 쿼리는 age_certification이 실제 NULL인 행만 조회한다.

여기서 중요한 건, 빈 문자열은 이 조건에 걸리지 않는다는 점이다.

즉 결과가 없다고 해서 “등급 없는 데이터가 없다”라고 결론 내리면 안 된다.

단지 NULL 형태로 저장된 값이 없는 것일 수 있다.

빈 문자열은 = ’’로 확인한다

문자열 컬럼이 비어 있는 경우는 보통 아래처럼 확인한다.

SELECT *
FROM titles
WHERE age_certification = '';

이 쿼리는 값이 NULL은 아니지만, 문자열 내용이 비어 있는 행을 찾는다.

실무에서 많이 헷갈리는 포인트가 바로 여기다.

IS NULL 결과가 안 나와서 문제없다고 생각했는데, 실제로는 ''가 많이 들어 있어서 필터링이 꼬이는 경우가 흔하다.

즉 IS NULL과 = ''는 거의 세트로 확인하는 편이 좋다.

등급 없는 데이터를 제외할 때 흔한 실수

예를 들어 영화 데이터에서 연령 등급별 개수를 집계한다고 해보자.

이때 “등급 없는 데이터는 제외”하려고 아래처럼 쓰는 경우가 많다.

WHERE age_certification IS NOT NULL

문제는 데이터가 NULL이 아니라 빈 문자열로 들어 있다면, 이 조건만으로는 등급 없는 데이터가 여전히 남는다.

반대로 아래처럼만 쓰는 것도 완전하지 않을 수 있다.

WHERE age_certification != ''

이 조건은 빈 문자열은 걸러내지만, NULL 비교는 예상과 다르게 동작할 수 있다.

즉 결측 방식이 혼합돼 있다면 둘 다 고려해야 한다.

실전에서는 이렇게 필터링하는 게 안전하다

age_certification이 비어 있는 값을 제외하고, 영화만 대상으로 연령 등급 Top 5를 보고 싶다면 아래처럼 쓰는 방식이 실전에서 더 안전하다.

SELECT
    age_certification,
    COUNT(1) AS Cnt
FROM titles
WHERE age_certification != ''
  AND type = 'MOVIE'
GROUP BY age_certification
ORDER BY Cnt DESC
LIMIT 5;

이 쿼리는 가이드 기준으로는 빈 문자열을 제외하고 영화만 대상으로 집계하는 방식이다.

다만 실제 데이터에서 NULL까지 함께 존재할 가능성이 있다면, 아래처럼 조건을 더 명시적으로 쓰는 것도 좋다.

SELECT
    age_certification,
    COUNT(1) AS Cnt
FROM titles
WHERE age_certification IS NOT NULL
  AND age_certification != ''
  AND type = 'MOVIE'
GROUP BY age_certification
ORDER BY Cnt DESC
LIMIT 5;

즉 핵심은 문법 하나를 외우는 게 아니라,

현재 데이터가 NULL 중심인지, 빈 문자열 중심인지 확인한 뒤 조건을 정하는 것이다.

NULL과 빈 문자열을 같이 볼 때 체크할 것

실무에서 이 문제를 빠르게 점검하려면 아래 순서로 보면 된다.

1) 값 종류 확인

SELECT DISTINCT age_certification
FROM titles;

2) NULL 개수 확인

SELECT COUNT(1)
FROM titles
WHERE age_certification IS NULL;

3) 빈 문자열 개수 확인

SELECT COUNT(1)
FROM titles
WHERE age_certification = '';

이렇게 먼저 점검하면, 이후 집계나 필터링에서 어떤 조건을 써야 하는지 훨씬 명확해진다.

왜 이게 데이터 분석에서 중요하냐

이 문제는 단순한 SQL 문법 차이로 끝나지 않는다.

결측 처리 방식을 잘못 이해하면 아래 같은 문제가 생긴다.

  • 연령 등급 분포가 왜곡됨
  • 특정 범주 개수가 실제보다 크게 나옴
  • “값 없는 데이터는 제외했다”는 가정이 틀림
  • 후속 분석 결과가 전부 어긋남

즉 데이터 분석에서 NULL과 빈 문자열 구분은 선택이 아니라 기본 검증 단계에 가깝다.

특히 범주형 컬럼은 한 번 집계해버리면 결과만 보고는 원인을 놓치기 쉬워서, 집계 전에 결측 표현 방식부터 확인하는 것이 중요하다.

실전에서 자주 하는 실수

1) IS NULL만 쓰고 끝내는 경우

결측처럼 보여도 실제론 빈 문자열일 수 있다. 이 경우 NULL만 확인하면 데이터가 남는다.

2) != ''만 쓰고 끝내는 경우

빈 문자열은 제외되지만, NULL 처리까지 충분히 고려하지 못할 수 있다.

3) DISTINCT 없이 바로 집계하는 경우

컬럼 상태를 확인하지 않고 바로 GROUP BY로 가면, 이상한 값이 왜 남는지 뒤늦게 찾게 된다.

4) 공백 문자열을 놓치는 경우

어떤 데이터는 ''가 아니라 ' '처럼 공백으로 들어 있을 수도 있다.

이 경우엔 TRIM() 같은 정제 함수까지 검토해야 한다.

정리

SQL에서 NULL과 빈 문자열은 둘 다 비어 보일 수 있지만, 실제로는 완전히 다른 값이다. 그래서 범주형 컬럼을 분석할 때는 바로 필터를 거는 것보다 먼저 값 종류를 확인하고, IS NULL과 = ''를 각각 점검해야 한다.

특히 age_certification 같은 컬럼은 등급 없는 데이터를 제외했다고 생각해도, 결측 표현 방식이 다르면 결과가 달라질 수 있다. 결국 중요한 건 특정 문법을 외우는 게 아니라, 이 컬럼에서 결측이 어떤 형태로 저장돼 있는지 먼저 확인하는 것이다.


SQL에서 결측처럼 보이는 값은 전부 NULL이 아니다. 분석 전에 IS NULL과 빈 문자열('')을 따로 확인하는 습관이 필요하다.