우선, 아래의 쿼리를 살펴보자.
select 1 = 1, --true
1 != 2, -- true
1 = null, -- null
null = null, -- null
null != null, -- null
1 != null, -- null
1 is null, -- false
1 is not null, -- true
null is null, -- true
null is not null; -- false
위의 쿼리 결과를 보고 두가지 의문이 든다.
- 일반값의 비교는 = 혹은 != 로 하면서 왜 null 의 비교는 is 혹은 is not 을 쓸까?
- 1 = null 과 1 != null 의 결과가 false, true 일거같은데 왜 null이 나올까?
의문을 해결하기위해선 SQL 에서 NULL의 의미를 알아야한다.
SQL 에서의 NULL의 의미
- unknown : 아직 알려지지 않았다는 뜻 -> 모름
- unavailable or withheld : 보안상의 이유 등으로 정보를 공개하지 않아 DB에 저장되지 않았다는 뜻 -> 비공개
- not applicable : 아예 해당사항이 없다는 뜻 -> 빈값
예시 설명
person
id | name | birth_date | company_name |
1 | Khan | 19900530 | 2ndsyndrome |
2 | Lee | 19940703 | NULL |
위와 같이 Lee의 회사이름(company_name)이 NULL로 되어있다면 아래 세가지를 의미한다.
- 알려지지 않음 (모름)
- 개인정보를 공개하지 않음 (비공개)
- 둘다 무직 (빈값)
NULL과 Three-Valued Logic
쿼리에서 null이 어떻게 동작하는지 살펴보자.
select * from person where company_name = '2ndsyndrome'
위의 쿼리에서 name이 Lee 인 데이터는 company_name이 NULL이기때문에 아직 모르거나, 비공개이거나, 빈값을 의미한다.
그 의미는 company_name이 2ndsyndrome일 확률 이 있다는것을 의미하므로 결과값이 TRUE 일수도있고, FALSE 일수도 있다.
따라서 NULL = '2ndsyndrome' 의 결과값은 NULL (UNKNWON)이 되므로, NULL 값을 비교할때는 일반적인 비교연산이 아닌 is NULL, is not NULL을 써야한다.
- Three-Valued Logic: SQL의 비교/논리 연산의 결과로 TRUE, FALSE, UNKNWON을 가진다. (일반적인 프로그래밍에서의 비교연산의 결과가 TRUE/FALSE로 구분되는것과는 다르게)
응용
select 3 in (1, 2, 4), -- false
3 in (1, 2, 3), -- true
3 in (1, 3, NULL), -- true
3 in (1, 2, NULL); -- unknown
Three-Valued Logic를 기반으로 위의 쿼리의 결과를 해석해보자면
- 3 in (1, 2, 4) 는 3이 1,2,4 안에 없는게 확실하므로 -> false
- 3 in (1, 2, 3) 는 3이 1,2,3 안에 있는게 확실하므로 -> true
- 3 in (1, 3, NULL) 는 3이 1,3, NULL 안에 있는게 확실하므로 -> true (NULL 값이 뭔진 모르겠지만 일단 3 in 3을 만족하므로)
- 3 in (1, 2, NULL) 는 3이 1,2, NULL 안에 있는게 불확실하므로 -> unknown (NULL 값이 뭔지 잘모르겠지만, 그거에 따라 결과가 달라진다고 해석가능)
주의사항
SQL의 Three-Valued Logic 으로 인해 쿼리 작성시 주의 해야할 점이 있다.
쿼리 작성시 where 조건절을 준 경우 조건절의 결과가 TRUE 인 tuple만 선택이 된다.
즉, 조건절의 결과가 FALSE와 UNKNWON은 선택되지 않는다.
따라서, 조건절에 NULL이 포함될수 있는 subquery를 사용할경우 원하는 결과가 나오지 않을수 있다.
참고
https://www.youtube.com/watch?v=y_7rOoOodCY&list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&index=7
'게으른개발자 > 공부' 카테고리의 다른 글
Kafka Streams 파티션 할당 과정 (2) | 2024.10.18 |
---|---|
DB(PostgreSQL) 인덱스와 활용방법 (컴포지트 인덱스, 커버링 인덱스) (0) | 2023.03.13 |
gRPC 간단 정리와 예제 (0) | 2023.02.25 |
OSI 7Layer와 L1, L2, L3, L4, L7 스위치 (0) | 2022.10.30 |
REST vs. RESTful (0) | 2022.09.13 |