sourcetip

NOT IN 절 내부의 NULL 값

fileupload 2023. 4. 28. 21:16
반응형

NOT IN 절 내부의 NULL 값

는 제가 하여 서로 다른 레코드 수를 얻었을 때 했습니다.not in where a 약과다른aleft join에 표not in제약 조건에 하나의 null 값(잘못된 데이터)이 있으며 이로 인해 쿼리에서 0개의 레코드 수를 반환했습니다.이유는 어느 정도 이해하지만 개념을 완전히 파악하는 데 도움이 필요합니다.

간단히 말하자면, 왜 A 쿼리는 결과를 반환하지만 B는 반환하지 않습니까?

A: select 'true' where 3 in (1, 2, 3, null)
B: select 'true' where 3 not in (1, 2, null)

SQL Server 2005에 대한 내용입니다.는 또한 나는또그소이명한에 전화하는 했습니다.set ansi_nulls offB가 결과를 반환하도록 합니다.

쿼리 A는 다음과 같습니다.

select 'true' where 3 = 1 or 3 = 2 or 3 = 3 or 3 = null

때부터3 = 3사실입니다. 결과를 얻을 수 있습니다.

쿼리 B는 다음과 같습니다.

select 'true' where 3 <> 1 and 3 <> 2 and 3 <> null

ansi_nulls켜져 있습니다.3 <> null알 수 없으므로 술어가 알 수 없음으로 평가되고 행이 표시되지 않습니다.

ansi_nulls 짐꺼3 <> null참이므로 술어가 참으로 평가되고 행이 표시됩니다.

NOT IN알 수 없는 값과 비교할 때 0개의 레코드를 반환합니다.

때부터NULL는 알 수 알수없음▁a,, aNOT IN가 된 쿼리NULL또는NULL한 값 가한값는목의 s상항반환을 반환합니다.0 때문에 합니다.NULL값이 테스트 중인 값이 아닙니다.

NULL을 사용할 때마다 3값 논리를 실제로 처리하게 됩니다.

첫 번째 쿼리는 WHERE 절이 평가하는 결과를 반환합니다.

    3 = 1 or 3 = 2 or 3 = 3 or 3 = null
which is:
    FALSE or FALSE or TRUE or UNKNOWN
which evaluates to 
    TRUE

두 번째:

    3 <> 1 and 3 <> 2 and 3 <> null
which evaluates to:
    TRUE and TRUE and UNKNOWN
which evaluates to:
    UNKNOWN

UNKNOWN은 FALSE와 동일하지 않습니다. 다음을 호출하여 쉽게 테스트할 수 있습니다.

select 'true' where 3 <> null
select 'true' where not (3 <> null)

두 쿼리 모두 결과를 제공하지 않습니다.

UNKNOWN이 FALSE와 동일한 경우 첫 번째 쿼리가 FALSE를 제공한다고 가정하면 두 번째 쿼리는 NOT(FALSE)와 동일하므로 TRUE로 평가해야 합니다.
그렇지 않습니다.

SqlServerCentral에 이 주제에 대한 매우 좋은 기사가 있습니다.

NULL과 3값 논리의 전체적인 문제는 처음에는 약간 혼란스러울 수 있지만 TSQL에 올바른 쿼리를 작성하기 위해서는 반드시 이해해야 합니다.

SQL Aggregate Functions와 NULL을 추천합니다.

IS NULL을 사용하지 않는 한 null과 비교는 정의되지 않습니다.

따라서 3을 NULL(쿼리 A)과 비교하면 정의되지 않은 값이 반환됩니다.

즉, 3 in(1,2,null)인 경우 'true'를 선택하고 3 in(1,2,null)이 아닌 경우 'true'를 선택합니다.

NOT(미정의)가 여전히 정의되지 않았지만 TRUE는 아니기 때문에 동일한 결과를 생성합니다.

NULL을 포함하는 하위 쿼리에 대해 NOT IN으로 필터링하려면 Null이 아닌지 확인하십시오.

SELECT blah FROM t WHERE blah NOT IN
        (SELECT someotherBlah FROM t2 WHERE someotherBlah IS NOT NULL )

글을 쓸 당시 이 질문의 제목은

SQL NOT IN 제약 조건 및 NULL 값

한 것 .SELECT DDL이 CONSTRAINT.

하지만, 특히 제목의 문구를 고려할 때, 여기서 이루어진 일부 진술은 잠재적으로 오해를 불러일으킬 수 있는 진술이라는 점을 지적하고 싶습니다. (문단)

술어가 UNKNOWN으로 평가되면 행이 없습니다.

SQL DML의 경우에도 마찬가지이지만 제약 조건을 고려할 때 효과는 다릅니다.

질문의 술어에서 직접 가져온 두 가지 제약 조건(@Brannon의 훌륭한 답변으로 설명됨)이 있는 매우 간단한 표를 생각해 보십시오.

DECLARE @T TABLE 
(
 true CHAR(4) DEFAULT 'true' NOT NULL, 
 CHECK ( 3 IN (1, 2, 3, NULL )), 
 CHECK ( 3 NOT IN (1, 2, NULL ))
);

INSERT INTO @T VALUES ('true');

SELECT COUNT(*) AS tally FROM @T;

@Brannon의 대답에 따르면, 첫 번째 제약 조건은 다음과 같습니다.IN는두 번째 조건( )은 TRUE로 평가합니다.NOT IN)는 UNKNOWN으로 평가됩니다.그러나 삽입은 성공합니다!따라서 이 경우 행을 삽입했기 때문에 "행이 표시되지 않습니다."라고 말하는 것은 정확하지 않습니다.

위의 효과는 SQL-92 표준과 관련하여 정확한 효과입니다.SQL-92 사양의 다음 섹션을 비교 및 대조합니다.

7.6 where 절

의 결과는 검색 조건의 결과가 참인 T 행의 표입니다.

4.10 무결성 제약 조건

테이블의 행에 대해 지정된 검색 조건이 거짓이 아닌 경우에만 테이블 검사 제약 조건이 충족됩니다.

즉, 다음과 같습니다.

행은 SQL DML의 경우 됩니다.WHERE조건 "참"을 만족하지 않으므로 UNKNOWN으로 평가됩니다.

SQL DDL(즉, 제약 조건)에서 행은 "거짓이 아닙니다" 조건을 충족하므로 UNKNOWN으로 평가될 때 결과에서 제거되지 않습니다.

SQL DML과 SQL DDL의 효과가 각각 모순적으로 보일 수 있지만, UNKNOWN 결과가 제약 조건을 충족할 수 있도록 허용함으로써 '의심의 이점'을 제공하는 실질적인 이유가 있습니다(더 정확하게는, 이러한 행동 없이도 제약 조건을 충족하지 못하게 함).모든 제약 조건은 null을 명시적으로 처리해야 하며 언어 설계 관점에서 매우 불만족스러울 것입니다(코더에게는 말할 것도 없고, 올바른 고통입니다!).

p.s. "알 수 없는 것이 제약을 만족시키지 못한다"와 같은 논리를 따르는 것이 저처럼 어렵다면 SQL DDL 및 SQL DML에서 null을 생성하는 모든 열(예: 외부 조인)을 피하는 것만으로 이 모든 것을 생략할 수 있다고 생각하십시오!

A에서 3은 집합의 각 구성원에 대해 동일성을 검정하여 산출합니다(FALSE, FALSE, TRUE, UNKNOWN).요소 중 하나가 TRUE이므로 조건은 TRUE입니다. (여기서 일부 단락이 발생할 수도 있으므로 첫 번째 TRUE에 도달하는 즉시 실제로 중지되며 3=DICOM을 평가하지 않습니다.)

B에서는 NOT(3 in (1,2,null))로 조건을 평가하고 있는 것 같습니다.설정된 수율(FALSE, FALSE, UNKNOWN)에 대해 동일성을 테스트하는 3은 UNKNOWN으로 집계됩니다. NOT(UNKNOWN)은 UNKNOWN을 생성합니다.따라서 전체적으로 그 조건의 진실은 알 수 없으며, 결국에는 근본적으로 FALSE로 취급됩니다.

SQL은 참 값에 대해 세 값의 논리를 사용합니다.IN쿼리는 예상 결과를 생성합니다.

SELECT * FROM (VALUES (1), (2)) AS tbl(col) WHERE col IN (NULL, 1)
-- returns first row

하지만 추가하는 것NOT결과를 반전시키지 않습니다.

SELECT * FROM (VALUES (1), (2)) AS tbl(col) WHERE NOT col IN (NULL, 1)
-- returns zero rows

이는 위의 쿼리가 다음과 같기 때문입니다.

SELECT * FROM (VALUES (1), (2)) AS tbl(col) WHERE NOT (col = NULL OR col = 1)

where 절을 평가하는 방법은 다음과 같습니다.

| col | col = NULL⁽¹⁾  | col = 1 | col = NULL OR col = 1 | NOT (col = NULL OR col = 1) |
|-----|----------------|---------|-----------------------|-----------------------------|
| 1   | UNKNOWN        | TRUE    | TRUE                  | FALSE                       |
| 2   | UNKNOWN        | FALSE   | UNKNOWN⁽²⁾            | UNKNOWN⁽³⁾                  |

주의:

  1. ▁를 포함하는 비교.NULL 확량수UNKNOWN
  2. OR도 식TRUE의 피연산자는 그고적어하피연는자산의나도리입니다.UNKNOWN 확량수UNKNOWN(ref)
  3. NOTUNKNOWN 확량수UNKNOWN(ref)

를 두 개값(NULL, 1 및 할 수 값중가 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "NULL일치하는 행이 없습니다.

Null은 데이터가 없음을 나타냅니다. 즉, 알 수 없으며 데이터 값이 0이 아닙니다.프로그래밍 배경을 가진 사람들이 이것을 혼동하는 것은 매우 쉽습니다. 왜냐하면 C타입 언어에서 포인터를 사용할 때 null은 실제로 아무것도 아니기 때문입니다.

따라서 첫 번째 경우 3은 (1,2,3,null)의 집합에 있으므로 true가 반환됩니다.

하지만 두 번째에는 그것을 줄일 수 있습니다.

'true'를 선택합니다. 여기서 3은 (계속) 안에 없습니다.

따라서 사용자가 비교하고 있는 집합에 대해 파서가 아무것도 모르기 때문에 아무것도 반환되지 않습니다. 빈 집합이 아니라 알 수 없는 집합입니다.(1, 2, null)을 사용하는 것은 (1, 2) 집합이 명백히 거짓이기 때문에 도움이 되지 않지만, 알 수 없는 것에 대해 이를 수행하는 것입니다.

여기서의 답변으로 결론을 내릴 수 있습니다.NOT IN (subquery) Null을 .NOT EXISTS그러나 그러한 결론은 시기상조일 수 있습니다.Date ( 및 . 2 9,은 Chris Date (1989년 9월 9일자)입니다.NOT IN Null을 결과를합니다.NOT EXISTS.

.sp공급업체를 대표함(sno ( ).pno ( ) 수량(수()qty 에는 현재 과 같은 값이

      VALUES ('S1', 'P1', NULL), 
             ('S2', 'P1', 200),
             ('S3', 'P1', 1000)

수량을 알 수 없는 경우에도 공급업체가 부품을 공급하는 것으로 알려진 사실을 기록할 수 있는 수량은 무효입니다.

이 작업은 공급 부품 번호 'P1'로 알려져 있지만 수량이 1000개가 아닌 공급업체를 찾는 것입니다.

은 음다용을 사용합니다.NOT IN공급업체 'S2'만 올바르게 식별:

WITH sp AS 
     ( SELECT * 
         FROM ( VALUES ( 'S1', 'P1', NULL ), 
                       ( 'S2', 'P1', 200 ),
                       ( 'S3', 'P1', 1000 ) )
              AS T ( sno, pno, qty )
     )
SELECT DISTINCT spx.sno
  FROM sp spx
 WHERE spx.pno = 'P1'
       AND 1000 NOT IN (
                        SELECT spy.qty
                          FROM sp spy
                         WHERE spy.sno = spx.sno
                               AND spy.pno = 'P1'
                       );

그러나 아래 쿼리는 동일한 일반 구조를 사용하지만 다음을 포함합니다.NOT EXISTS그러나 공급업체 'S1'이 결과에 잘못 포함됩니다(즉, 수량이 null인 경우).

WITH sp AS 
     ( SELECT * 
         FROM ( VALUES ( 'S1', 'P1', NULL ), 
                       ( 'S2', 'P1', 200 ),
                       ( 'S3', 'P1', 1000 ) )
              AS T ( sno, pno, qty )
     )
SELECT DISTINCT spx.sno
  FROM sp spx
 WHERE spx.pno = 'P1'
       AND NOT EXISTS (
                       SELECT *
                         FROM sp spy
                        WHERE spy.sno = spx.sno
                              AND spy.pno = 'P1'
                              AND spy.qty = 1000
                      );

그렇게NOT EXISTS그것이 나타났을지도 모르는 은색 총알이 아닙니다!

물론, 문제의 근원은 null의 존재이기 때문에 '진짜' 해결책은 이러한 null을 제거하는 것입니다.

이는 두 개의 표를 사용하여 (다른 가능한 설계 중에서도) 달성할 수 있습니다.

  • sp을 공급하는
  • spq .

여기에는 아마도 키 조건이 있어야 점에 합니다.spqsp.

그런 ' 수 .EXCEPTSQL를 들어 SQL의 키워드를 지정할 수 있습니다.

WITH sp AS 
     ( SELECT * 
         FROM ( VALUES ( 'S1', 'P1' ), 
                       ( 'S2', 'P1' ),
                       ( 'S3', 'P1' ) )
              AS T ( sno, pno )
     ),
     spq AS 
     ( SELECT * 
         FROM ( VALUES ( 'S2', 'P1', 200 ),
                       ( 'S3', 'P1', 1000 ) )
              AS T ( sno, pno, qty )
     )
SELECT sno
  FROM spq
 WHERE pno = 'P1'
EXCEPT 
SELECT sno
  FROM spq
 WHERE pno = 'P1'
       AND qty = 1000;

이것은 소년을 위한 것입니다.

select party_code 
from abc as a
where party_code not in (select party_code 
                         from xyz 
                         where party_code = a.party_code);

이것은 ansi 설정에 상관없이 작동합니다.

또한 이것은 조인, 존재 및 http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx 의 논리적 차이를 아는 데 유용할 수 있습니다.

언급URL : https://stackoverflow.com/questions/129077/null-values-inside-not-in-clause

반응형