NULL
SQL에서 NULL의 의미
- unknown
- ex: 누군가의 생일 정보가 null로 처리되었다. 분명 그 사람의 생일은 존재함. 생일이 아직 알려지지 않았다는 것.
- unavailable or withheld
- ex: 본인의 생일 정보를 공개하지 않은 것. 민감한 개인 정보일수도 있기에. 따라서 생일 정보를 이용할 수 없다.
- not applicable
- ex: 요즘은 집 전화가 잘 없음. 집 전화 정보를 저장하려는 경우, 집 전화 자체가 없으면 아예 해당사항이 없는 것. 즉 적용할 수 없음, 해당사항이 아닌 것.
-> SQL에서는 이러한 다양한 의미를 하나의 NULL로 표시
- id가 14, 15인 두 임직원의 생일이 둘 다 NULL이라고 해서 '두 분의 생일이 동일하다' 이렇게 볼 수 없음.
- 업데이트를 하지 않았거나 공개를 하지 않았을 뿐
- 이 두 분의 생일은 같을 수도 있고, 다를 수도 있음
- SQL에서 NULL과 비교할 때는 같다, 혹은 다르다고 단정지을 수 없음
- 실행 결과, 아무것도 가져오지 않음
- 아무것도 가져오지 않았으니, "employee table에서 birth_date 정보가 NULL인 것은 아무것도 없나보다" 라고 생각X
- NULL과 비교할 때는 같다(=) 라는 비교 연산자 사용X
- IS 연산자 사용해야, 제대로 된 결과 나옴
- NULL과 같은지 아닌지 비교하기 위해서는 IS 연산자 사용해야 함!
NULL과 Three-Valued Logic
- SQL에서 NULL과 비교 연산을 하게 됐을 때, 그 결과를 어떻게 처리하게 되는지 살펴보자
- 생일이 1990-03-09인 임직원을 조회하는 SELECT문을 실행한다고 해보자
- birth_date column에서 1990-03-09 을 찾는 도중, NULL 발견
- 이 NULL과 비교하면, 1990-03-09이 아니기에 각각에 대해 비교 연산의 결과가 FALSE를 return한다고 생각하기 쉬움
- BUT, SQL에서는 NULL이 여러가지 의미를 가짐
- 생일 정보 공개하지 않았거나, 아직 업데이트 되지 않았거나, 알려지지 않아서 NULL일 뿐
- 다를 가능성이 더 크지만, 이 분들의 생일이 1990-03-09과 같을 수도 있음.
- 그럼 SQL에서는 NULL과 비교 연산했을 때 어떻게 처리?
- SQL에서 NULL과 비교 연산을 하게 되면 그 결과는 UNKNOWN이다
- UNKNOWN은 'TRUE일수도 있고 FALSE일 수도 있다'라는 의미이다
- three-valued logic: 비교/논리 연산의 결과로 TRUE, FALSE, UNKNOWN을 가진다
- 어떤 연산자를 가지고 비교를 하든, NULL과 비교를 할때는 UNKNOWN이 된다.
- 심지어 NULL과 NULL을 비교할 때도 UNKNOWN이 된다.
- NULL이라는 값이 만약에 실제로 어떤 유효한 값을 가질 수 있었다면
- 어떤 값인지에 따라서 이들 결과가 TURE일수도 있고 FALSE일수도 있기 때문에
- 이런 경우에 SQL은 UNKNOWN으로 처리한다.
- 비교 연산을 수행할 때, 어느 한쪽에 NULL이 있으면 그 결과는 무조건 UNKNOWN이 된다.
AND, OR, NOT의 논리 연산에 대해 UNKNOWN을 포함하게 되면 어떻게 될까
cf. 논리 연산자(and, or, not)
and: 논리식이 모두 참이면 참을 반환함
or: 논리식 중에서 하나라도 참이면 참을 반환함
not: 논리식의 결과가 참이면 거짓을, 거짓이면 참을 반환
- 논리 연산을 수행할 때, UNKNOWN이 포함되면 어떤 결과가 나올지 잘 알아두어야 함!
- 잘 알아둬야 하는 이유는 다음과 같음
WHERE 절의 condition(s)
- where 절에 있는 condition(s)의 결과가 TRUE인 tuple(s)만 선택된다
- 즉, 결과가 FALSE거나 UNKNOWN이면 TUPLE은 선택되지 않는다
- 이 부분을 잘 인식하고 있어야, SQL을 작성하고 나서 예상치 못한 동작이 발생했을 때 혼란에 빠지지 않을 수 있음
NOT IN 사용 시 주의 사항
- v NOT IN (v1, v2, v3)는 아래와 같은 의미이다
- v != v1 AND v != v2 AND v != v3
- 만약 v1, v2, v3 중에 하나가 NULL이라면?
- 부서의 id 중에 NULL이 있다고 가정 (ex: 아직 부서 배치를 받지 않아서 부서의 id를 임시로 NULL로 처리)
- 어떤 경우에도 TRUE는 나올 수 없기에, 결국 SELECT문이 반환하는 결과는 아무것도 없음
- 우리가 예상한대로 동작하지 않게 됨
- 실제로 2000년대생이 없는 부서가 있다고 할지라도, 그 어떤 부서도 반환하지 않음
이 문제를 해결하기 위해서는
- 애초에 employee table에서 dept_id가 NULL값을 가질 수 없도록 NOT NULL constraints 걸어두기
- subquery에서 dept_id가 NOT NULL인 경우를 CHECK해서 subquery가 return하는 값이 NULL을 포함하지 않도록
- NOT IN을 NOT EXISTS로 바꿔서 처리