ใน SQL Server“ SET ANSI_NULLS ON” หมายความว่าอย่างไร


92

คำจำกัดความกล่าวว่า:

เมื่อ SET ANSI_NULLS เปิดอยู่คำสั่ง SELECT ที่ใช้ WHERE column_name = NULL จะส่งกลับศูนย์แถวแม้ว่าจะมีค่า null ใน column_name ก็ตาม คำสั่ง SELECT ที่ใช้ WHERE column_name <> NULL ส่งคืนแถวศูนย์แม้ว่าจะมีค่าที่ไม่ใช่ null ใน column_name ก็ตาม

นี่หมายความว่าจะไม่มีการรวมค่าว่างในแบบสอบถามนี้หรือไม่?

SELECT Region
FROM employees
WHERE Region = @region

หรือANSI_NULLกังวลเฉพาะคำถามเช่นนี้ (ซึ่งWHEREรวมถึงคำเฉพาะNULL)?

SELECT Region
FROM employees
WHERE Region = NULL

1
คำตอบที่ไม่มีอยู่ในย่อหน้าที่ 4 ของเอกสารอย่างเป็นทางการที่คุณคัดลอกย่อหน้าที่ 1 คือ: -> "SET ANSI_NULLS ON มีผลต่อการเปรียบเทียบก็ต่อเมื่อหนึ่งในตัวถูกดำเนินการของการเปรียบเทียบเป็นตัวแปรที่เป็น NULL หรือค่า NULL ตามตัวอักษรหากทั้งสองด้านของการเปรียบเทียบเป็นคอลัมน์หรือนิพจน์ผสมการตั้งค่าจะไม่มีผลต่อการเปรียบเทียบ "
user1451111

คำตอบ:


68

หมายความว่าจะไม่มีการส่งคืนแถวถ้า@regionเป็นNULLเมื่อใช้ในตัวอย่างแรกของคุณแม้ว่าจะมีแถวในตารางRegionอยู่NULLก็ตาม

เมื่อANSI_NULLSเปิด (ซึ่งคุณควรตั้งค่าไว้เสมอเนื่องจากตัวเลือกที่จะไม่เปิดใช้งานจะถูกลบออกในอนาคต) การดำเนินการเปรียบเทียบใด ๆ ที่ (อย่างน้อย) ตัวถูกดำเนินการตัวใดตัวหนึ่งNULLสร้างค่าลอจิกที่สาม - UNKNOWN( ซึ่งตรงข้ามกับTRUEและFALSE)

UNKNOWNค่าเผยแพร่ผ่านการรวมผู้ประกอบการบูลีนถ้าพวกเขาไม่ได้ตัดสินใจแล้วใด ๆ (เช่นANDมีFALSEตัวถูกดำเนินการหรือORมีTRUEตัวถูกดำเนินการ) หรือ negations ( NOT)

ส่วนWHEREคำสั่งใช้เพื่อกรองผลลัพธ์ที่กำหนดโดยFROMอนุประโยคเพื่อให้ค่าโดยรวมของWHEREอนุประโยคต้องเป็นTRUEเพื่อไม่ให้แถวถูกกรองออก ดังนั้นหากUNKNOWNเกิดจากการเปรียบเทียบใด ๆ ก็จะทำให้แถวนั้นถูกกรองออก


คำตอบของ @ user1227804 รวมถึงคำพูดนี้:

หากทั้งสองด้านของการเปรียบเทียบเป็นคอลัมน์หรือนิพจน์ผสมการตั้งค่าจะไม่มีผลต่อการเปรียบเทียบ

จาก*SET ANSI_NULLS

อย่างไรก็ตามฉันไม่แน่ใจว่าจุดใดที่พยายามสร้างขึ้นเนื่องจากหากNULLมีการเปรียบเทียบสองคอลัมน์ (เช่นใน a JOIN) การเปรียบเทียบยังคงล้มเหลว:

create table #T1 (
    ID int not null,
    Val1 varchar(10) null
)
insert into #T1(ID,Val1) select 1,null

create table #T2 (
    ID int not null,
    Val1 varchar(10) null
)
insert into #T2(ID,Val1) select 1,null

select * from #T1 t1 inner join #T2 t2 on t1.ID = t2.ID and t1.Val1 = t2.Val1

คำค้นหาด้านบนส่งคืน 0 แถวในขณะที่:

select * from #T1 t1 inner join #T2 t2 on t1.ID = t2.ID and (t1.Val1 = t2.Val1 or t1.Val1 is null and t2.Val1 is null)

ส่งคืนหนึ่งแถว ดังนั้นแม้เมื่อทั้งสองตัวถูกดำเนินการที่มีคอลัมน์ไม่เท่ากับNULL NULLและเอกสารสำหรับ=ไม่มีอะไรจะพูดเกี่ยวกับตัวถูกดำเนินการ:

เมื่อคุณเปรียบเทียบสองNULLนิพจน์ผลลัพธ์จะขึ้นอยู่กับการANSI_NULLSตั้งค่า:

หากANSI_NULLSตั้งค่าONเป็นผลลัพธ์คือNULL1ตามข้อตกลง ANSI ว่าค่าNULL(หรือไม่ทราบ) ไม่เท่ากับค่าอื่นNULLหรือไม่ทราบ

หากANSI_NULLSมีการตั้งค่าOFF, ผลมาจากการNULLเทียบกับมีNULLTRUE

การเปรียบเทียบNULLกับNULLค่าที่ไม่ใช่จะให้ผลลัพธ์เป็นFALSE2เสมอ

อย่างไรก็ตามทั้ง1และ2ไม่ถูกต้อง - UNKNOWNผลของการเปรียบเทียบทั้งสองคือ


* ในที่สุดความหมายที่คลุมเครือของข้อความนี้ก็ถูกค้นพบในอีกหลายปีต่อมา ความหมายที่แท้จริงก็คือสำหรับการเปรียบเทียบเหล่านั้นการตั้งค่าจะไม่มีผลใด ๆ และจะทำหน้าที่เหมือนกับว่าการตั้งค่านั้นเปิดอยู่เสมอ จะชัดเจนกว่านี้หากระบุว่าSET ANSI_NULLS OFFเป็นการตั้งค่าที่ไม่มีผลกระทบ


1
ดังนั้นถ้าฉันเข้าใจคุณถูกต้องมันจะส่งผลต่อผลลัพธ์ของวลี "Where Region = @region" ด้วยและไม่เพียง แต่เมื่อฉันเขียนเฉพาะ "Where Region = null" เท่านั้น
Rodniko

7

ถ้า@Regionไม่ใช่nullค่า (สมมติว่า@Region = 'South') จะไม่ส่งคืนแถวที่ฟิลด์ภูมิภาคเป็นโมฆะโดยไม่คำนึงถึงค่าของ ANSI_NULLS

ANSI_NULLS จะสร้างความแตกต่างก็ต่อเมื่อค่า@Regionเป็นnullเท่านั้นกล่าวคือเมื่อแบบสอบถามแรกของคุณกลายเป็นคำที่สอง

ในกรณีนั้น ANSI_NULLS ON จะไม่ส่งคืนแถวใด ๆ (เนื่องจากnull = nullจะให้ค่าบูลีนที่ไม่รู้จัก (aka null)) และ ANSI_NULLS OFF จะส่งคืนแถวใด ๆ ที่เขตข้อมูลภูมิภาคเป็นโมฆะ (เพราะnull = nullจะให้ผลtrue)


6

ถ้า ANSI_NULLS ตั้งค่าเป็น "ON" และถ้าเราใช้ =, <> กับค่าคอลัมน์ NULL ในขณะที่เขียนคำสั่ง select ก็จะไม่ส่งคืนผลลัพธ์ใด ๆ

ตัวอย่าง

create table #tempTable (sn int, ename varchar(50))

insert into #tempTable
values (1, 'Manoj'), (2, 'Pankaj'), (3, NULL), (4, 'Lokesh'), (5, 'Gopal')

ตั้งค่า ANSI_NULLS บน

select * from #tempTable where ename is NULL -- (1 row(s) affected)
select * from #tempTable where ename = NULL -- (0 row(s) affected)
select * from #tempTable where ename is not NULL -- (4 row(s) affected)
select * from #tempTable where ename <> NULL -- (0 row(s) affected)

ตั้งค่า ANSI_NULLS ปิด

select * from #tempTable where ename is NULL -- (1 row(s) affected)
select * from #tempTable where ename = NULL -- (1 row(s) affected)
select * from #tempTable where ename is not NULL -- (4 row(s) affected)
select * from #tempTable where ename <> NULL -- (4 row(s) affected)

2
+1 เพื่อเป็นคำตอบเดียวที่แยกความแตกต่างอย่างชัดเจนระหว่างWHERE X IS NULLและWHERE X = NULLและวิธีที่ ANSI_NULLS มีผลต่อผลลัพธ์ แม้จะมีความพยายามอย่างมากของผู้ลงคะแนนเสียงที่ลดลง แต่นี่ควรเป็นคำตอบที่ยอมรับ
Riegardt Steyn

1
+1 สำหรับการอธิบายโดยใช้ตัวอย่างซึ่งมักจะชัดเจนและกระชับมากกว่าประโยคยาว ๆ
peter.aryanto

3

ตั้งค่า ANSI_NULLS บน

IT ส่งคืนค่าทั้งหมดรวมทั้งค่า null ในตาราง

ปิด SET ANSI_NULLS

จะสิ้นสุดเมื่อคอลัมน์มีค่า null


2
คำตอบนี้เพิ่มอะไรให้กับคำตอบที่ระบุไว้แล้ว? ระวังการเพิ่มคำตอบใหม่สำหรับคำถามเก่า - ควรมีคำอธิบายเพิ่มเติมเกี่ยวกับโซลูชันที่โพสต์ไว้แล้วหรือให้ข้อมูลเชิงลึกใหม่ - จากการตรวจสอบ
Takarii

1

ฉันเดาว่าสิ่งสำคัญที่นี่คือ:

ไม่เคยเป็นผู้ใช้:

  • @anything = NULL
  • @anything <> NULL
  • @anything != null

ใช้เสมอ:

  • @anything IS NULL
  • @anything IS NOT NULL

0

การตั้งค่า ANSI NULLS OFF จะทำให้การเปรียบเทียบ NULL = NULL กลับมาเป็นจริง เช่น :

        SET ANSI_NULLS OFF
        select * from sys.tables
        where principal_id = Null

จะส่งคืนผลลัพธ์ตามที่แสดงด้านล่าง: zcwInvoiceDeliveryType 744547 NULL zcExpenseRptStatusTrack 2099048 NULL ZCVendorPermissions 2840564 NULL ZCWOrgLevelClientFee 4322525 NULL

แม้ว่าการสืบค้นนี้จะไม่แสดงผลลัพธ์ใด ๆ :

        SET ANSI_NULLS ON 
        select * from sys.tables
        where principal_id = Null

0

https://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-nulls-transact-sql

เมื่อ SET ANSI_NULLS เปิดอยู่คำสั่ง SELECT ที่ใช้ WHERE column_name = NULL จะส่งกลับศูนย์แถวแม้ว่าจะมีค่า null ใน column_name ก็ตาม คำสั่ง SELECT ที่ใช้ WHERE column_name <> NULL ส่งคืนแถวศูนย์แม้ว่าจะมีค่าที่ไม่เป็นศูนย์ใน column_name ก็ตาม

สำหรับเช่น

DECLARE @TempVariable VARCHAR(10)
SET @TempVariable = NULL

SET ANSI_NULLS ON
SELECT 'NO ROWS IF SET ANSI_NULLS ON' where    @TempVariable = NULL
-- IF ANSI_NULLS ON , RETURNS ZERO ROWS


SET ANSI_NULLS OFF
SELECT 'THERE WILL BE A ROW IF ANSI_NULLS OFF' where    @TempVariable =NULL
-- IF ANSI_NULLS OFF , THERE WILL BE ROW !
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.