[sql] SQL Server에서 NULL = NULL이 false로 평가되는 이유
SQL Server nullParam=NULL
에서 where 절이 있으면 항상 false로 평가됩니다. 이것은 직관적이지 않으며 많은 오류를 일으켰습니다. 키워드 IS NULL
와 IS NOT NULL
키워드가 올바른 방법임을 이해합니다 . 그러나 왜 SQL 서버가 이런 식으로 작동합니까?
답변
이 경우 널을 “알 수 없음”으로 생각하십시오 (또는 “존재하지 않음”). 두 경우 중 하나의 가치를 알지 못하기 때문에 둘이 같다고 말할 수 없습니다. 따라서 null = null은 값이 같은지 알 수 없으므로 시스템에 따라 false 또는 null이 아닌 것으로 평가됩니다 (시스템에 따라 false 또는 null). 이 동작은 ANSI SQL-92 표준에 정의되어 있습니다.
편집 : 이것은 ansi_nulls 설정 에 따라 다릅니다 . ANSI_NULLS가 꺼져 있으면이 값은 true로 평가됩니다. 예를 들어 다음 코드를 실행하십시오 …
set ansi_nulls off
if null = null
print 'true'
else
print 'false'
set ansi_nulls ON
if null = null
print 'true'
else
print 'false'
답변
프랭크는 몇 살입니까? 모르겠습니다 (널).
셜리는 몇 살입니까? 모르겠습니다 (널).
Frank와 Shirley는 같은 나이입니까?
Frank와 Shirley 가 같은 나이 일 수 있기 때문에 정답은 “모름”이 아니라 “아니오” 여야합니다. 우리는 단순히 모릅니다.
답변
여기 내 희망을 분명히 밝힐 것입니다.
그 NULL = NULL
에 평가는 FALSE
잘못된 것입니다. 해커와 미스터가 올바르게 대답했습니다 NULL
. 이유는 다음과 같습니다. Dewayne Christensen은 Scott Ivey 에 대한 의견으로 저에게 썼습니다. .
12 월 이후 계절별 예제를 사용해 보겠습니다. 나무 밑에 선물이 두 개 있습니다. 자, 내가 똑같은 것을 얻었는지 말 해주세요.
그것들은 다를 수도 있고 같을 수도 있습니다 . 둘 다 선물을 열 때까지 알 수 없습니다 . 누가 알아? 서로를 모르고 둘 다 같은 선물을 한 두 사람을 초대했습니다. 드물지만 불가능하지는 않습니다. § .
질문 :이 두 알 수없는 동일한 (=, 같음)을 제시합니까? 정답은 다음과 같습니다. UNKNOWNNULL
입니다.
이 예는 보여주기 위해 의도 된 그 “.. ( false
또는 null
, 시스템에 따라하는) …”정답입니다 – 그것은하지 않습니다 만 NULL
3VL 정확합니다 (또는 오답을주는 시스템을 수락해도 괜찮습니까? )
이 질문에 대한 정답 은 다음 두 가지 을 강조해야합니다.
- 3 값 논리 (3VL)는 직관적이지 않습니다 (스택 오버플로 및 기타 포럼에서이 주제에 대한 수많은 다른 질문을 참조하십시오).
- SQL 기반 DBMS는 종종 3VL조차도 존중하지 않으며 때로는 잘못된 답변을 제공합니다 (원래 포스터가 주장하는 것처럼 SQL Server는이 경우).
그래서 나는 반복한다 : SQL은 평등의 재귀 속성을 해석하도록 강요하지 않는다.
for any x, x = x
§§ (일반 영어 : 담론의 세계가 무엇이든 “사물”은 항상 자신과 같습니다 ).
3VL에서의 .. ( TRUE
, FALSE
, NULL
). 사람들의 기대는 2VL ( TRUE
,, FALSE
심지어 SQL에서도 다른 모든 값에 유효합니다)을 준수 x = x
합니다. TRUE
예외없이 – X의 가능한 값.
또한 NULL은 ” 관계 변수의 일부로 속성 값 (??)으로 할당 할 수 값이 아닌 “(죄 학자가 주장하는 것처럼)입니다. 따라서 논리 표현식 유형뿐만 아니라 모든 유형 (도메인)에 허용되는 값입니다.
그리고 이것은 내 요점이었다 . NULL
가치로서 “이상한 짐승”이다. 완곡 성이 없다면 나는 말하기를 선호한다. 말도 안된다. .
이 공식은 훨씬 명확하고 논쟁의 여지가 없다고 생각합니다. 저의 영어 실력이 유감입니다.
이것은 NULL 문제 중 하나 일뿐 입니다. 가능하면 완전히 피하는 것이 좋습니다.
§ 우리는 가치 에 대해 염려 한다 여기서 하므로 두 선물이 항상 두 개의 다른 물리적 대상이라는 사실은 유효한 반대가 아닙니다. 당신이 내가 미안하다고 확신하지 않는다면, 이것이 가치와 “객체”의미의 차이점을 설명하는 곳이 아닙니다 (관계 대수는 처음부터 가치 의미가 있습니다-Codd의 정보 원리 참조; 일부 SQL DBMS 구현자는 공통 의미론조차 신경 쓰지 않습니다).
§§ 내 지식에 따르면, 이것은 고대부터 인정 된 공리 (형태 또는 다른 형태이지만 항상 2VL로 해석 됨)입니다. 정확히 그렇게 직관적이기 때문입니다. 3VL (실제로 논리 계열)은 훨씬 최근의 개발이지만 처음 개발 된시기는 확실하지 않습니다.
참고 : 누군가가 Bottom , Unit 및 SQL NULL을 정당화하기 위해 Option Types를 NULL을 사용한 SQL 구현에 사운드 유형 시스템이 어떻게 있는지를 보여주는 매우 상세한 검사 후에 만 확신 할 것입니다. NULL (이것들은 “quite-not-quite-values”)이 실제로 무엇인가.
다음에 나는 몇몇 저자들을 인용 할 것이다. 모든 오류 또는 누락은 아마도 원저자에 의한 것이 아니라 내 것입니다.
SQL NULL의 Joe Celko
Joe Celko가이 포럼에서 자주 인용 한 것을 보았습니다. 분명히 그는 여기에서 존경받는 작가입니다. “나는 그가 SQL NULL에 대해 무엇을 썼는가? NULL에 수많은 문제를 어떻게 설명 하는가?” 내 친구 중 하나의 전자 책 버전이 있습니다 스마트 폰을위한 Joe Celko의 SQL : 고급 SQL 프로그래밍, 3 판을 가지고 있습니다. 보자
먼저 목차. 가장 많이 눈에 띄는 것은 NULL이 언급 된 횟수와 가장 다양한 상황입니다.
3.4 산술 및 NULL 109
3.5 NULL로 값 변환 및 NULL 110
3.5.1 NULLIF () 함수 110
6 NULL : SQL 185에서 데이터 누락
6.4 NULL 비교 190
6.5 NULL 및 논리 190
6.5.1 하위 쿼리 조건 자에서 NULL 191
6.5.2 표준 SQL 솔루션 193
6.6 수학 및 NULL 193
6.7 함수 및 NULL 193
6.8 NULL 및 호스트 언어 194
6.9 NULL에 대한 설계 조언 195
6.9.1 호스트 프로그램에서 NULL 방지 197
6.10 다중 NULL 값에 대한 참고 사항 198
10.1 IS NULL 조건 자 241
10.1. 1 NULL 소스 242
…
등등. 나에게 “불쾌한 특별한 경우”를 울린다.
나는이 책에서 발췌 한 일부 사례에 대해 저작권의 이유로 본질적인 것으로 제한하려고 노력할 것이다. 나는이 인용문들이 “공정한 사용”교리에 속한다고 생각하며 책을 사도록 자극 할 수도있다. 그래서 아무도 불평하지 않기를 바란다. 또한 동일한 이유로 코드 스 니펫보고를 삼가야합니다. 미안합니다. 데이터에 근거한 추론에 대해 읽으려면 책을 구입하십시오.
다음에 나오는 괄호 안의 페이지 번호입니다.
NOT NULL 제약 조건 (11)
가장 중요한 열 제약 조건은 NOT NULL로, 열에서 NULL 사용을 금지합니다. 이 제한 조건을 일상적으로 사용하고 정당한 이유가있는 경우에만 제거하십시오. 데이터에 대해 쿼리 할 때 NULL 값 의 합병증을 피하는 데 도움이됩니다 .
값이 아닙니다 . 값이 갈 수있는 장소를 보유하는 마커입니다.
다시 말하지만이 “값은 아니지만 값”은 의미가 없습니다. 나머지는 나에게 현명 해 보인다.
(12)
요컨대, NULL은 SQL에서 많은 불규칙한 기능을 유발하므로 나중에 설명하겠습니다. 가장 좋은 방법은 상황과 피할 수없는 NULL 규칙을 외우는 것입니다.
SQL, NULL 및 무한의 제안 :
제 3 장 : SQL의 숫자 데이터
SQL은 여러 가지 이유로 수학에 대한 IEEE 모델을 승인하지 않았습니다.
…
수학에 대한 IEEE 규칙이 SQL에서 허용 된 경우 무한에 대한 유형 변환 규칙과 변환 후 무한 정확한 숫자 값을 나타내는 방법이 필요합니다. 사람들은 NULL에 충분한 문제가 있으므로 거기에 가지 마십시오.
특정 컨텍스트에서 NULL이 실제로 의미하는 바에 따라 SQL 구현이 결정되지 않았습니다.
3.6.2 지수 함수 (116)
문제는 (x <= 0) 일 때 로그가 정의되지 않는다는 것입니다. 일부 SQL 구현 은 오류 메시지를 리턴하고 일부는 NULL 및 DB2 / 400을 리턴합니다 . 버전 3 릴리스 1은 결과로 * NEGINF ( “음의 무한대”의 약자)를 리턴했습니다.
Joe Celko는 David McGoveran과 CJ Date를 인용했습니다.
6 개의 NULL : SQL에서 데이터 누락 (185)
David McGoveran과 CJ Date는 자신의 Sybase 및 SQL Server에 대한 안내서에서 “현재 SQL에 정의되고 구현 된 것처럼 NULL보다이 작가의 견해는 가치보다 훨씬 더 많은 문제이며 피해야합니다. 그것들은 매우 이상하고 일관성이없는 행동을 나타내며 풍부한 오류와 혼란의 원인이 될 수 있습니다. (이러한 의견과 비판은 SQL Server뿐만 아니라 SQL 스타일 NULL을 지원하는 모든 시스템에 적용됩니다. “
약물 중독 으로서의 NULL :
(186/187)
이 책의 나머지 부분에서, 나는 당신에게 그것들을 사용하지 말 것을 요구할 것입니다. 약물로 NULL을 생각하십시오. 올바르게 사용하면 효과가 있지만 남용하면 모든 것을 망칠 수 있습니다. 최선의 정책은 가능한 한 NULL을 피하고 필요할 때 적절하게 사용하는 것입니다.
여기에서의 저의 독특한 반대는 “적절하게 사용”하는 것인데, 이는 특정 구현 행동과 심하게 상호 작용합니다.
6.5.1 하위 쿼리 조건 자에서의 NULLS (191/192)
하위 쿼리는 종종 NULL과의 비교를 숨기는 것을 잊습니다. 다음 두 테이블을 고려하십시오.
…
결과는 비어 있습니다. 이것은 반 직관적 이지만 정확합니다.
(분리 기호)
6.5.2 표준 SQL 솔루션 (193)
SQL-92는 새로운 형식의 술어를 추가하여 3VL (3 값 논리) 문제 중 일부를 해결했습니다.
<검색 조건> IS [NOT] TRUE | 거짓 | 알 수 없는
그러나 UNKNOWN은 그 자체로 문제의 원인이되므로 아래에 인용 된 CJ Date는 4.5 장에서 권장됩니다 . SQL에서 Null 피하기 :
- 어떤 상황에서도 키워드 UNKNOWN을 사용하지 마십시오.
UNKNOWN에서 “ASIDE” 를 읽으십시오 ( 아래 링크도 참조).
6.8 NULL과 호스트 언어 (194)
그러나 널 (NULL)이 호스트 프로그램으로 전달 될 때 널이 처리되는 방식을 알아야합니다. 임베드가 정의 된 표준 호스트 언어는 NULL을 지원하지 않으므로 데이터베이스 스키마에서 NULL을 사용하지 않는 것이 좋습니다.
(분리 기호)
6.9 NULL에 대한 설계 조언 (195)
가능하면 모든 열에 NOT NULL 제약 조건을 사용하여 모든 기본 테이블을 선언하는 것이 좋습니다. NULL은 SQL을 모르는 사람들을 혼란스럽게하며 NULL은 비쌉니다.
이의 제기 : NULL은 SQL을 잘 아는 사람들도 혼동합니다 (아래 참조).
(195)
FOREIGN KEY에서는 NULL을 피해야합니다. SQL은 이러한“의심의 이점”관계를 허용하지만 조인과 관련된 쿼리에서 정보가 손실 될 수 있습니다. 예를 들어 Orders 테이블에서 FOREIGN KEY로 참조되는 Inventory의 부품 번호 코드가 제공되면 NULL이있는 부품 목록을 가져 오는 데 문제가 있습니다. 이것은 필수 관계입니다. 존재하지 않는 부품은 주문할 수 없습니다.
(분리 기호)
6.9.1 호스트 프로그램에서 NULL 피하기 (197)
일부 프로그래밍 규칙을 사용하여 호스트 프로그램에서 데이터베이스에 NULL을 넣지 않도록 할 수 있습니다.
…
- 누락 된 데이터가 프로그래밍 및보고에 미치는 영향 확인 :
집계 함수를 사용하는 쿼리는 잘못된 결과를 제공 할 수 있으므로 NULL이있는 숫자 열은 문제가됩니다.
(분리 기호)
(227)
빈 세트의 SUM ()은 항상 NULL입니다. 이 트릭을 사용할 때 발생하는 가장 일반적인 프로그래밍 오류 중 하나는 둘 이상의 행을 반환 할 수있는 쿼리를 작성하는 것입니다. 당신이 그것에 대해 생각하지 않았다면, 당신은 마지막 예제를 다음과 같이 썼을 것입니다 : …
(분리 기호)
10.1.1 NULL 소스 (242)
NULL이 발생할 수있는 위치를 기억하는 것이 중요합니다. 그것들은 열에서 가능한 값 이상의 것 입니다. 빈 세트, OUTER JOIN, NULL이있는 산술 표현식 및 OLAP 연산자의 집계 함수는 모두 NULL을 반환합니다. 이러한 구성은 종종 VIEW에서 열로 표시됩니다.
(분리 기호)
(301)
IN 술어를 EXISTS 술어로 변환하려고 할 때 널 (NULL)에 대한 다른 문제점이 있습니다.
(분리 기호)
16.3 ALL 술어 및 극단 함수 (313)
처음에이 두 술어가 SQL에서 동일하지 않다는 것은 직관적이지 않습니다.
…
그러나 극단 함수에 대한 규칙을 기억해야합니다. 더 크거나 가장 작은 값을 반환하기 전에 모든 NULL을 제거합니다. ALL 술어는 NULL을 삭제하지 않으므로 결과에서 얻을 수 있습니다.
(분리 기호)
(315)
그러나 표준의 정의는 음수로 표시되므로 NULL은 의심의 이점을 얻습니다. …
보시다시피 UNIQUE 제약 조건에서 NULL을 피하는 것이 좋습니다.
GROUP BY 논의 :
NULL은 모두 서로 같은 것으로 취급되며 자체 그룹을 형성합니다. 그런 다음 각 그룹은 이전 결과를 대체하는 새 결과 테이블에서 단일 행으로 줄어 듭니다.
이는 GROUP BY 절의 경우 NULL = NULL은 3VL에서와 같이 NULL로 평가되지 않지만 TRUE로 평가됨을 의미합니다.
SQL 표준은 혼란 스럽습니다.
ORDER BY 및 NULL (329)
NULL 인 정렬 키 값이 NULL이 아닌 값보다 크거나 작은 것으로 간주되는지 여부는 구현에서 정의되지만 …
… 어느 쪽이든 SQL 제품이 있습니다.
1999 년 3 월 Chris Farrar는 개발자 중 한 사람에게 질문을 제기하여 내가 이해했다고 생각한 SQL 표준의 일부 를 조사하게되었습니다 . Chris 는 본 명세서의 일반적인 이해와 실제 표현 사이에 약간의 차이점을 발견 했습니다 .
등등. Celko로는 충분하다고 생각합니다.
SQL NULL에 대한 CJ 날짜
CJ Date는 NULL에 대해 더 급진적입니다. SQL에서 NULL을 피하십시오. 사실, 그의 SQL 및 관계 이론의 4 장 : 정확한 SQL 코드 작성 방법 은 제목이 “4.4 Null에 무엇이 잘못 되었습니까?” 라는 제목의 “NO DUPLICATES, NO NULLS
“입니다. 및 “4.5 SQL에서 Null 사용 방지”(링크를 따르십시오. Google 도서 덕분에 일부 페이지를 온라인으로 읽을 수 있습니다).
SQL NULL에 대한 Fabian Pascal
데이터베이스 관리 의 실제 문제-사고 실무자를위한 참고 자료 (발췌 없음, 죄송합니다) :
10.3 실질적 의미
10.3.1 SQL NULL
… SQL은 많은 단점, 복잡성, 반 직관성 및 명백한 오류뿐만 아니라 3VL 고유의 문제로 인해 어려움을 겪고 있습니다 [10, 11]. 그중에는 다음이 있습니다.
- 집계 함수 (예 : SUM (), AVG ())는 NULL을 무시합니다 (COUNT () 제외).
- 행이없는 테이블의 스칼라 표현식은 0 대신 NULL로 잘못 평가됩니다.
- “NULL = NULL”표현식은 NULL로 평가되지만 실제로는 SQL에서 유효하지 않습니다. 그러나 ORDER BY는 NULL을 동일하게 취급합니다 ( “정규”값보다 먼저 또는 뒤에 오는 것은 DBMS 공급 업체에 남습니다).
- “V IS NOT NULL”표현식은 2VL에서와 같이 “NOT (x IS NULL)”와 같지 않습니다.
…
상업적으로 구현 된 모든 SQL 언어는이 3VL 방식을 따르므로 이러한 문제를 해결할뿐만 아니라 제품마다 다른 특수 구현 문제가 있습니다 .
답변
어쩌면 그것은 달려 있지만 , 피연산자로 NULL을 사용하는 대부분의 연산 NULL=NULL
을 NULL
좋아 한다고 생각 합니다.
답변
두 가지가 무엇인지 알지 못한다고해서 둘이 같다는 것은 아닙니다. 당신이 생각할 때 경우에 NULL
당신이 “NULL”(문자열) 생각 당신은 아마도 PostgreSQL을의 같은 평등의 다른 테스트 할 IS DISTINCT FROM
AND를IS NOT DISTINCT FROM
“비교 함수 및 연산자” 에 대한 PostgreSQL 문서에서
표현
IS DISTINCT FROM
표현표현
IS NOT DISTINCT FROM
표현널이 아닌 입력의
IS DISTINCT FROM
경우<>
연산자 와 동일합니다 . 그러나 두 입력이 모두 null이면 false를 반환하고 하나의 입력 만 null이면 true를 반환합니다. 마찬가지로 널이 아닌 입력의 경우와IS NOT DISTINCT FROM
동일=
하지만 두 입력이 모두 널이면 true를, 하나의 입력 만 널이면 false를 리턴합니다. 따라서 이러한 구성은 “알 수없는”것이 아니라 null이 일반 데이터 값인 것처럼 효과적으로 작동합니다.
답변
NULL의 개념은 가장 의문의 여지가 있습니다. Codd는 문맥에서 관계형 모델과 NULL의 개념을 소개하고 (2 종 이상의 NULL을 제안하기 위해 계속되었습니다!) 그러나 관계형 이론은 Codd의 최초 저술 이후 진화했습니다. 다른 사람들은 절대로 붙 잡지 않았습니다 (예 : 세타 운영자). 현대의 관계 이론에서 (진실한 관계 이론에서 나는 스트레스를 받아야한다) NULL은 존재하지 않는다. 세 번째 선언문을 참조하십시오. http://www.thethirdmanifesto.com/
SQL 언어는 이전 버전과의 호환성 문제가 있습니다. NULL은 SQL에서 그 길을 찾았고 우리는 그것에 붙어 있습니다. 아마도 NULL
SQL에서 의 구현에 결함이 있습니다 (SQL Server의 구현으로 인해 SQL Server의 구현이 훨씬 복잡해집니다)ANSI_NULLS
옵션 ).
기본 테이블에서 NULL 가능 열을 사용하지 않는 것이 좋습니다.
아마도 유혹을 받아서는 안되지만 NULL
SQL에서 작동 하는 방식에 대한 내 자신의 수정 사항을 주장하고 싶었습니다 .
NULL
=로 NULL
평가됩니다 UNKNOWN
.
UNKNOWN
논리 값입니다.
NULL
데이터 값입니다.
이것은 증명하기 쉽다.
SELECT NULL = NULL
SQL Server에서 오류를 올바르게 생성합니다. 결과가 데이터 값이면 NULL
여기에 일부 답변이 잘못 제안한 것처럼을 볼 수 있습니다.
논리적 값 UNKNOWN
은 SQL DML과 SQL DDL에서 각각 다르게 취급됩니다.
SQL DML에서는 UNKNOWN
결과 집합에서 행이 제거됩니다.
예를 들면 다음과 같습니다.
CREATE TABLE MyTable
(
key_col INTEGER NOT NULL UNIQUE,
data_col INTEGER
CHECK (data_col = 55)
);
INSERT INTO MyTable (key_col, data_col)
VALUES (1, NULL);
는 INSERT
짝수 불구하고,이 행에 성공 CHECK
조건을 해결합니다 NULL = NULL
. 이는 SQL-92 ( “ANSI”) 표준에 정의되어 있습니다.
11.6 테이블 제약 조건 정의
삼)
테이블 제한 조건이 점검 제한 조건 정의 인 경우, SC를 점검 제한 조건 정의에 즉시 포함 된 검색 조건으로하고 T를 해당 테이블 제한 조건 설명자에 포함 된 테이블 이름으로하십시오. 다음과 같은 경우에만 테이블 제한 조건이 충족되지 않습니다.
기존 (선택하지 않은 곳에서 선택 * (SC))
사실이다.
논리에 따라 다시주의 깊게 읽으십시오.
평범한 영어로, 위의 새로운 행에는 ‘의심의 혜택’이 주어지고 UNKNOWN
통과하는 것이 허용됩니다.
SQL DML에서 WHERE
절의 규칙 을 따르는 것이 훨씬 쉽습니다.
탐색 조건은 T의 각 행에 적용됩니다. where 절의 결과는 탐색 조건의 결과가 참인 T의 행에 대한 테이블입니다.
평범한 영어로 평가되는 행 UNKNOWN
은 결과 집합에서 제거됩니다.
답변
에서 TechNet의 방법 널 (null) 값 작업에 대한 좋은 설명이있다.
널은 알 수 없음을 의미합니다.
따라서 부울 식
값 = 널
false로 평가되지 않고 null로 평가되지만 where 절의 최종 결과 인 경우 아무 것도 반환되지 않습니다. null을 반환하는 것은 임신하기 어렵 기 때문에 그렇게하는 실용적인 방법입니다.
다음을 이해하는 것이 흥미롭고 매우 중요 합니다.
쿼리에서 우리는
where (value=@param Or @param is null) And id=@anotherParam
과
- 값 = 1
- @param이 null입니다
- id = 123
- @ anotherParam = 123
그때
“value = @ param”
은 null로 평가되고 “@param은 null”은 true로 평가됩니다.
“id = @ anotherParam”은 true로 평가됩니다.
평가할 표현은
(null 또는 true) 그리고 사실
여기서 “null Or true”는 null로 평가되어 전체 표현식이 null이되고 행이 반환되지 않는다고 생각할 수도 있습니다.
그렇지 않습니다. 왜?
“null Or true”는 매우 논리적 인 true로 평가되기 때문에 하나의 피연산자가 Or 연산자로 true이면 다른 피연산자의 값에 관계없이 연산이 true를 리턴하므로 매우 논리적입니다. 따라서 다른 피연산자를 알 수없는 것은 중요하지 않습니다 (널).
결국 우리는 true = true를 가지므로 행이 반환됩니다.
참고 : “null Or true”가 true로 평가되는 것과 동일한 수정 논리를 사용하면 “null And true”가 null로 평가됩니다.
업데이트 :
좋아, 그냥 완성하기 위해 여기에 나머지를 추가하고 싶습니다. 위와 관련하여 꽤 재미 있습니다.
“null Or false”는 null로 평가되고 “null And false”는 false로 평가됩니다. 🙂
논리는 물론 이전과 마찬가지로 여전히 자명합니다.