ค่า NULL ภายใน NOT IN clause


245

ปัญหานี้ขึ้นมาเมื่อฉันได้นับระเบียนที่แตกต่างกันสำหรับสิ่งที่ฉันคิดว่าเป็นคำสั่งที่เหมือนหนึ่งใช้not in whereข้อ จำกัด left 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 offทำให้ B ส่งคืนผลลัพธ์

คำตอบ:


283

ข้อความค้นหา 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คือ UNKNOWN ดังนั้นเพรดิเคตจะประเมิน UNKNOWN และคุณจะไม่ได้รับแถวใด ๆ

เมื่อansi_nullsปิดใช้งาน3 <> nullจะเป็นจริงดังนั้นเพรดิเคตจะประเมินเป็นจริงและคุณจะได้รับแถว


11
มีใครเคยชี้ให้เห็นว่าการแปลงNOT INเป็นชุด<> andการเปลี่ยนแปลงพฤติกรรมเชิงความหมายของการไม่ได้อยู่ในชุดนี้เป็นอย่างอื่น?
Ian Boyd

8
@Ian - ดูเหมือนว่า "A NOT IN ('X', 'Y')" จริง ๆ แล้วเป็นนามแฝงสำหรับ A <> 'X' และ A <> 'Y' ใน SQL (ฉันเห็นว่าคุณค้นพบสิ่งนี้ด้วยตัวเองในstackoverflow.com/questions/3924694/…แต่ต้องการตรวจสอบให้แน่ใจว่าการคัดค้านของคุณได้รับการแก้ไขในคำถามนี้)
Ryan Olson

ฉันเดาว่านี่จะอธิบายว่าทำไมSELECT 1 WHERE NULL NOT IN (SELECT 1 WHERE 1=0);ให้ผลตอบแทนหนึ่งแถวแทนชุดผลลัพธ์ที่ว่างเปล่าที่ฉันคาดไว้
binki

2
นี่เป็นพฤติกรรมที่แย่มากของเซิร์ฟเวอร์ SQL เพราะหากคาดว่าจะใช้การเปรียบเทียบแบบ NULL โดยใช้ "IS NULL" คุณควรขยายส่วนคำสั่งในลักษณะการทำงานเดียวกันและไม่ใช้ความหมายที่ผิดพลาดอย่างโง่เขลากับตัวเอง
OzrenTkalcecKrznaric

@binki คุณรันแบบสอบถามถ้าวิ่งที่นี่rextester.com/l/sql_server_online_compilerแต่ไม่ทำงานถ้าวิ่งที่นี่sqlcourse.com/cgi-bin/interpreter.cgi
Istiaque Ahmed

53

เมื่อใดก็ตามที่คุณใช้ NULL คุณกำลังเผชิญกับตรรกะสามค่า

ข้อความค้นหาแรกของคุณจะส่งคืนผลลัพธ์เมื่อส่วนคำสั่ง 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 ที่สองจะต้องประเมินเป็น TRUE เพราะจะเป็นเหมือนกับ NOT (FALSE)
ไม่เป็นเช่นนั้น

มีดีมากเป็นบทความเกี่ยวกับเรื่องนี้ใน SqlServerCentral

ปัญหาทั้งหมดของ NULL และลอจิกสามค่าอาจสร้างความสับสนเล็กน้อยในตอนแรก แต่มันเป็นสิ่งสำคัญที่จะต้องเข้าใจเพื่อที่จะเขียนแบบสอบถามที่ถูกต้องใน TSQL

บทความอื่นฉันอยากจะแนะนำคือฟังก์ชั่นการรวม sql และเป็นโมฆะ


33

NOT IN ส่งกลับ 0 ระเบียนเมื่อเปรียบเทียบกับค่าที่ไม่รู้จัก

เนื่องจากNULLไม่เป็นที่รู้จักNOT INแบบสอบถามที่มีNULLหรือNULLs ในรายการค่าที่เป็นไปได้จะส่งกลับ0ระเบียนเสมอเนื่องจากไม่มีวิธีที่จะทำให้แน่ใจว่าNULLค่านั้นไม่ใช่ค่าที่ถูกทดสอบ


3
นี่คือคำตอบสั้น ๆ ฉันพบว่าสิ่งนี้ง่ายต่อการเข้าใจแม้ไม่มีตัวอย่างใด ๆ
Govind Rai

18

เปรียบเทียบกับ null ไม่ได้ถูกกำหนดเว้นแต่ว่าคุณใช้ IS NULL

ดังนั้นเมื่อเปรียบเทียบ 3 กับ NULL (เคียวรี A) จะส่งคืนค่าที่ไม่ได้กำหนด

Ie SELECT 'true' โดยที่ 3 ใน (1,2, null) และ SELECT 'true' โดยที่ 3 ไม่ได้อยู่ใน (1,2, null)

จะสร้างผลลัพธ์เดียวกันเนื่องจาก NOT (UNDEFINED) ยังไม่ได้กำหนด แต่ไม่ใช่ TRUE


จุดที่ดี เลือก 1 โดยที่ null ใน (null) จะไม่ส่งคืนแถว (ansi)
crokusek

9

ชื่อของคำถามนี้ในขณะที่เขียนคือ

SQL ไม่ได้อยู่ในข้อ จำกัด และค่า NULL

จากข้อความของคำถามก็ปรากฏว่าปัญหาที่เกิดขึ้นใน SQL DML SELECTแบบสอบถามมากกว่า CONSTRAINTDDL

อย่างไรก็ตามโดยเฉพาะอย่างยิ่งเมื่อได้รับถ้อยคำของชื่อฉันต้องการชี้ให้เห็นว่าบางข้อความที่ทำที่นี่เป็นข้อความที่อาจทำให้เข้าใจผิดซึ่งเป็นไปตามแนวของ (การถอดความ)

เมื่อเพรดิเคตประเมินเป็น 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 ข้อไหน

ผลลัพธ์ของการเป็นตารางของแถวเหล่านั้นของ T ซึ่งผลลัพธ์ของเงื่อนไขการค้นหาเป็นจริง

4.10 ข้อ จำกัด ด้านความซื่อสัตย์

ข้อ จำกัด การตรวจสอบตารางเป็นไปตามเงื่อนไขหากว่าเงื่อนไขการค้นหาที่ระบุไม่ใช่เท็จสำหรับแถวใด ๆ ของตาราง

ในคำอื่น ๆ :

ใน SQL DML แถวจะถูกลบออกจากผลลัพธ์เมื่อWHEREประเมินเป็น UNKNOWN เนื่องจากไม่มีตรงตามเงื่อนไข "เป็นจริง"

ใน SQL DDL ( จำกัด IE), แถวจะไม่ถูกลบจากผลที่ได้เมื่อพวกเขาประเมินไม่รู้จักเพราะมัน ไม่ตอบสนองเงื่อนไข "ไม่ได้เป็นเท็จ"

แม้ว่าลักษณะพิเศษใน SQL DML และ SQL DDL ตามลำดับอาจดูเหมือนขัดแย้งกัน แต่มีเหตุผลจริงที่ทำให้ UNKNOWN ให้ผลลัพธ์ 'ประโยชน์ของข้อสงสัย' โดยอนุญาตให้ตอบสนองข้อ จำกัด (ถูกต้องมากขึ้นทำให้ไม่สามารถตอบสนองข้อ จำกัด ได้) : หากไม่มีพฤติกรรมนี้ข้อ จำกัด ทุกอย่างจะต้องจัดการกับโมฆะอย่างชัดเจนและจะไม่เป็นที่น่าพอใจมากจากมุมมองการออกแบบภาษา (ไม่พูดถึงความเจ็บปวดที่ถูกต้องสำหรับโคเดอร์!)

ป.ล. ถ้าคุณพบว่ามันท้าทายที่จะทำตามตรรกะเช่น "ไม่รู้จักไม่ล้มเหลวในการตอบสนองข้อ จำกัด " อย่างที่ฉันเขียนมันแล้วพิจารณาว่าคุณสามารถแจกจ่ายสิ่งเหล่านี้ได้ง่ายๆเพียงแค่หลีกเลี่ยงคอลัมน์ nullable ใน SQL DDL และอะไรก็ได้ใน SQL DML ที่สร้าง nulls (เช่นการรวมภายนอก)!


ฉันไม่คิดว่าจะมีอะไรเหลือที่จะพูดในเรื่องนี้ น่าสนใจ
Jamie Ide

2
@Jamie Ide: จริงๆแล้วฉันมีคำตอบอีกเรื่อง: เนื่องจากการมีNOT IN (subquery)ค่า Null สามารถให้ผลลัพธ์ที่ไม่คาดคิดได้มันเป็นการพยายามหลีกเลี่ยงIN (subquery)อย่างสมบูรณ์และใช้เสมอNOT EXISTS (subquery)(อย่างที่ฉันเคยทำ! อย่างไรก็ตามมีหลายกรณีที่NOT IN (subquery)ให้ผลลัพธ์ที่คาดหวังในขณะที่NOT EXISTS (subquery)ให้ผลลัพธ์ที่ไม่คาดคิด! ฉันอาจใช้เวลาเขียนสิ่งนี้ขึ้นมา แต่ถ้าฉันสามารถหาโน้ตของฉันในหัวข้อ (ต้องการโน้ตเพราะมันไม่ง่ายเลย!) ข้อสรุปเหมือนกันแม้ว่า: หลีกเลี่ยงโมฆะ!
onedaywhen

@oneday เมื่อฉันสับสนกับการยืนยันของคุณว่า NULL จะต้องเป็นกรณีพิเศษที่จะมีพฤติกรรมที่สอดคล้องกัน (สอดคล้องกันภายในไม่สอดคล้องกับสเปค) มันจะไม่เพียงพอที่จะเปลี่ยน 4.10 เพื่ออ่าน "ข้อ จำกัด การตรวจสอบตารางจะพอใจถ้าหากเงื่อนไขการค้นหาที่ระบุเป็นจริง"?
DylanYoung

@DylanYoung: ไม่มีข้อมูลจำเพาะเป็นห่วงวิธีการที่เป็นเหตุผลสำคัญ: ทุกข์ SQL จากสามตรรกะค่าที่ค่าเหล่านั้นTRUE, และFALSE UNKNOWNฉันคิดว่า 4.10 สามารถอ่านได้ "ข้อ จำกัด การตรวจสอบตารางเป็นไปตามเงื่อนไขหากว่าเงื่อนไขการค้นหาที่ระบุเป็น TRUE หรือ UNKNOWN สำหรับทุกแถวของตาราง" - บันทึกการเปลี่ยนแปลงของฉันที่ส่วนท้ายของประโยค - ซึ่งคุณละเว้น - - จาก "สำหรับ" ใด ๆ "ถึง" สำหรับทุกคน "ฉันรู้สึกจำเป็นที่จะต้องใช้ประโยชน์จากค่าตรรกะเพราะความหมายของ 'จริง' และ 'เท็จ' ในภาษาธรรมชาติจะต้องอ้างถึงตรรกะสองค่าคลาสสิกแน่นอน
onedaywhen

1
พิจารณา: CREATE TABLE T ( a INT NOT NULL UNIQUE, b INT CHECK( a = b ) );- เจตนาที่นี่คือbต้องเท่ากันaหรือเป็นโมฆะ หากมีข้อ จำกัด ที่จะส่งผล TRUE จะได้รับความพึงพอใจจากนั้นเราก็จะต้องมีการเปลี่ยนแปลงข้อ จำกัด CHECK( a = b OR b IS NULL )ในการจัดการอย่างชัดเจนเช่น ดังนั้นข้อ จำกัด ทุกอย่างจะต้องมีการ...OR IS NULLเพิ่มตรรกะโดยผู้ใช้สำหรับแต่ละคอลัมน์ nullable ที่เกี่ยวข้อง: ความซับซ้อนมากขึ้นข้อผิดพลาดมากขึ้นเมื่อพวกเขาลืมที่จะทำเช่นนั้น ฯลฯ ดังนั้นฉันคิดว่าคณะกรรมการมาตรฐาน SQL ได้พยายามที่จะปฏิบัติ
oneday เมื่อ

7

ใน A, 3 จะได้รับการทดสอบเพื่อความเท่าเทียมกันกับสมาชิกแต่ละคนของเซตการยอมแพ้ (FALSE, FALSE, TRUE, UNKNOWN) เนื่องจากหนึ่งในองค์ประกอบคือ TRUE สภาพจึงเป็น TRUE (อาจเป็นไปได้ว่ามีการลัดวงจรเกิดขึ้นที่นี่ดังนั้นจึงหยุดทันทีที่พบกับ TRUE แรกและไม่เคยประเมิน 3 = NULL)

ใน B ฉันคิดว่ามันกำลังประเมินเงื่อนไขว่าไม่ใช่ (3 ใน (1,2, null)) การทดสอบ 3 เพื่อความเท่าเทียมกับชุดผลตอบแทน (FALSE, FALSE, UNKNOWN) ซึ่งรวมเข้ากับ UNKNOWN NOT (UNKNOWN) ให้ผลตอบแทน UNKNOWN ดังนั้นความจริงของสภาพโดยรวมจึงไม่เป็นที่รู้จักซึ่งท้ายที่สุดก็ถือว่าเป็น FALSE


7

มันอาจจะได้ข้อสรุปจากคำตอบที่นี่ที่NOT IN (subquery)ไม่ได้จัดการ nulls NOT EXISTSอย่างถูกต้องและควรหลีกเลี่ยงในความโปรดปรานของ อย่างไรก็ตามข้อสรุปดังกล่าวอาจจะคลอดก่อนกำหนด ในสถานการณ์ต่อไปนี้ให้เครดิตกับ Chris Date (การเขียนโปรแกรมฐานข้อมูลและการออกแบบ, Vol 2 No 9, กันยายน 1989), มันเป็นNOT INสิ่งที่จัดการ nulls อย่างถูกต้องและส่งกลับผลลัพธ์ที่ถูกต้องมากกว่าNOT EXISTSอย่างถูกต้องและผลตอบแทนผลที่ถูกต้องมากกว่า

พิจารณาตารางspเพื่อเป็นตัวแทนซัพพลายเออร์ ( sno) ที่รู้จักกันในการจัดหาชิ้นส่วน ( pno) ในปริมาณ ( qty) ตารางนี้มีค่าต่อไปนี้:

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

โปรดทราบว่าปริมาณเป็นโมฆะคือเพื่อให้สามารถบันทึกข้อเท็จจริงที่ซัพพลายเออร์เป็นที่รู้จักในการจัดหาชิ้นส่วนแม้ว่ามันจะไม่เป็นที่รู้จักในปริมาณใด

งานคือการค้นหาซัพพลายเออร์ที่เป็นที่รู้จักหมายเลขชิ้นส่วนอุปทาน 'P1' แต่ไม่ได้อยู่ในปริมาณ 1,000

การใช้งานต่อไปนี้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' ในผลลัพธ์ (เช่นซึ่งปริมาณเป็นโมฆะ):

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ไม่ใช่กระสุนเงินที่มันอาจปรากฏขึ้น!

แน่นอนที่มาของปัญหาคือการมีโมฆะดังนั้นทางออก 'ของจริง' คือการกำจัดโมฆะเหล่านั้น

สามารถทำได้ (ในการออกแบบอื่น ๆ ที่เป็นไปได้) โดยใช้สองตาราง:

  • sp ซัพพลายเออร์ที่รู้จักกันในการจัดหาชิ้นส่วน
  • spq ซัพพลายเออร์ที่รู้จักกันในการจัดหาชิ้นส่วนในปริมาณที่รู้จักกัน

สังเกตอาจมีควรจะเป็นข้อ จำกัด ที่สำคัญต่างประเทศที่อ้างอิงspqsp

ผลลัพธ์สามารถรับได้โดยใช้ตัวดำเนินการสัมพันธ์ 'ลบ' (เป็นEXCEPTคำหลักใน 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;

1
พระเจ้าช่วย. ขอบคุณจริง ๆ ที่เขียนสิ่งนี้ขึ้นมา .... นี่มันทำให้ฉันคลั่งไปเลย ..
วินด์เชียงราย

6

Null หมายถึงและไม่มีข้อมูลนั่นคือไม่เป็นที่รู้จักไม่ใช่ค่าข้อมูลใด ๆ มันง่ายมากสำหรับผู้ที่มีพื้นฐานการเขียนโปรแกรมเพื่อสร้างความสับสนเพราะในภาษาประเภท C เมื่อใช้พอยน์เตอร์พอยน์เตอร์นั้นก็ไม่มีอะไรเลย

ดังนั้นในกรณีแรก 3 จึงอยู่ในเซตของ (1,2,3, null) ดังนั้นจริงจะถูกส่งกลับ

ในครั้งที่สองอย่างไรก็ตามคุณสามารถลดมันได้

เลือก 'จริง' โดยที่ 3 ไม่อยู่ใน (null)

ดังนั้นไม่มีการส่งคืนเนื่องจาก parser ไม่รู้อะไรเกี่ยวกับชุดที่คุณกำลังเปรียบเทียบมัน - ไม่ใช่ชุดเปล่า แต่เป็นชุดที่ไม่รู้จัก การใช้ (1, 2, null) ไม่ได้ช่วยเพราะชุด (1,2) นั้นผิดพลาดอย่างเห็นได้ชัด แต่ถ้าอย่างนั้นคุณก็ไม่ทราบซึ่งไม่เป็นที่รู้จัก


6

ถ้าคุณต้องการที่จะกรองด้วย NOT IN สำหรับแบบสอบถามย่อยที่มี NULL เพียงแค่ตรวจสอบว่าไม่ใช่ null

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

ฉันมีปัญหากับแบบสอบถามแบบใช้ร่วมภายนอกที่ไม่ส่งคืนระเบียนใด ๆ ในสถานการณ์พิเศษดังนั้นให้ตรวจสอบโซลูชันนี้สำหรับทั้ง Null และสถานการณ์ที่มีอยู่ของระเบียนและทำงานได้สำหรับฉันหากมีปัญหาอื่นเกิดขึ้นฉันจะพูดถึงที่นี่ขอบคุณมาก
QMaster

1

นี่สำหรับเด็กผู้ชาย:

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

สิ่งนี้ทำงานโดยไม่คำนึงถึงการตั้งค่า ansi


สำหรับคำถามเดิม: B: เลือก 'true' โดยที่ 3 ไม่ได้อยู่ใน (1, 2, null) จะต้องทำวิธีลบ nulls เช่นเลือก 'จริง' โดยที่ 3 ไม่อยู่ใน (1, 2, isnull (null, 0) ) ตรรกะโดยรวมคือถ้า NULL เป็นสาเหตุจากนั้นหาวิธีลบค่า NULL ในบางขั้นตอนในแบบสอบถาม

เลือก party_code จาก abc เป็น party_code ไม่ได้อยู่ใน (เลือก party_code จาก xyz ที่ party_code ไม่ใช่ null) แต่โชคดีถ้าคุณลืมฟิลด์อนุญาต nulls ซึ่งมักจะเป็นกรณี

1

SQL ใช้ตรรกะสามค่าสำหรับค่าความจริง INแบบสอบถามจะให้ผลลัพธ์ที่คาดหวัง:

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

แต่การเพิ่ม a 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)

นี่คือวิธีการประเมินข้อที่:

| col | col = NULL (1) | col = 1 | col = NULL OR col = 1 | NOT (col = NULL OR col = 1) |
|-----|----------------|---------|-----------------------|-----------------------------|
| 1   | UNKNOWN        | TRUE    | TRUE                  | FALSE                       |
| 2   | UNKNOWN        | FALSE   | UNKNOWN (2)           | UNKNOWN (3)                 |

สังเกตว่า:

  1. การเปรียบเทียบที่เกี่ยวข้องกับNULLผลตอบแทนUNKNOWN
  2. ORแสดงออกที่ไม่มีตัวถูกดำเนินการที่มีTRUEและอย่างน้อยหนึ่งตัวถูกดำเนินการเป็นUNKNOWNอัตราผลตอบแทนUNKNOWN( โทษ )
  3. NOTของUNKNOWNอัตราผลตอบแทนUNKNOWN( โทษ )

คุณสามารถขยายตัวอย่างข้างต้นเป็นค่ามากกว่าสองค่า (เช่น NULL, 1 และ 2) แต่ผลลัพธ์จะเหมือนกัน: หากหนึ่งในค่าNULLนั้นไม่มีแถวจะไม่ตรงกัน


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.