최근 프로젝트에서 JSONB 타입 컬럼(auto_generated_tags)을 사용하면서 꽤 혼란스러운 상황을 겪었습니다.
DB를 조회해 보니 일부 데이터가 null로 표시되었는데, 실제로는 JSONB 내부에 "null" 값이 들어간 경우였습니다.
- JSON "null" → 컬럼 값은 존재하지만 내용이 JSON으로 "null"을 가지고 있음
처음엔 단순히 null로 표시된 걸 '{}' 로 변경하기 위해 아래처럼 쿼리했습니다.
UPDATE product_sample_images
SET auto_generated_tags = '{}'::jsonb
WHERE auto_generated_tags IS NULL;
하지만 결과적으로 여전히 null이 보였습니다. 왜냐하면 "null" 문자열은 IS NULL로 걸리지 않기 때문입니다.
이 문제를 해결하려면 다음과 같이 타입 캐스팅 후 체크가 필요했습니다:
UPDATE product_sample_images
SET auto_generated_tags = '{}'::jsonb
WHERE auto_generated_tags::text = 'null';
결론적으로, PostgreSQL의 NULL과 JSON의 "null"은 전혀 다르네요.
왜 이런 차이가 생길까? 그리고 ::는 뭘까?
PostgreSQL에서 JSONB 컬럼은 단순 문자열이 아니라 JSON 구조체를 내부적으로 파싱해 저장합니다.
이때 두 가지 상황이 발생합니다:
- DB 자체 NULL
- 해당 컬럼에 값이 아예 없는 상태
- SQL에서 IS NULL로 확인 가능
- JSON 내부 "null"
- JSON 구조체의 값이 null로 저장된 상태
- SQL 입장에서는 값이 있음 → 따라서 IS NULL에 걸리지 않음
결국 IS NULL은 DB 차원의 null만 잡을 뿐, JSON 내부 값은 따로 처리해야 합니다.
::는 무엇인가?
PostgreSQL에서는 :: 연산자가 타입 캐스팅(type casting) 을 의미합니다.
즉, 데이터를 다른 타입으로 변환하는 기능입니다.
예를 들어:
SELECT 123::text; -- 숫자 123 → 문자열 '123'로 변환
SELECT '{}'::jsonb; -- 문자열 '{}' → JSONB 객체로 변환
이렇게 하면 내부 구조를 문자열로 풀어서 "null"인지 확인할 수 있습니다.
JSONB 컬럼을 비교할 때도 마찬가지입니다:
WHERE auto_generated_tags::text = 'null';
이렇게 하면 내부 구조를 문자열로 풀어서 "null"인지 확인할 수 있습니다.
TL;DR:
- PostgreSQL에서 NULL과 JSON "null"은 다르다.
- "null" 처리는 jsonb 타입에 대해서 auto_generated_tags::text = 'null' 와 같은 타입 캐스팅이 필요하며, ::는 PostgreSQL의 타입 변환 연산자다.
'SQL' 카테고리의 다른 글
[SQL] 데이터 수정 (UPDATE, SET) (0) | 2022.02.23 |
---|---|
[SQL] 테이블 삭제 (DELETE FROM) (0) | 2022.02.23 |
[SQL] 데이터 삽입 (INSERT INTO) (0) | 2022.02.22 |
[SQL] 하위 쿼리( Sub-query) (0) | 2022.02.22 |
[SQL] 테이블 행 합치기 (UNION) (0) | 2022.02.22 |