ในทางเทคนิค NULL = NULL เป็นเท็จโดยตรรกะนั้น NULL จะเท่ากับ NULL ใด ๆ และ NULL ทั้งหมดนั้นแตกต่างกัน นี่ไม่ควรบอกเป็นนัยเลยว่า NULL ทั้งหมดนั้นไม่เหมือนใครและดัชนีที่ไม่ซ้ำกันควรอนุญาตให้มี NULL จำนวนเท่าใด?
ในทางเทคนิค NULL = NULL เป็นเท็จโดยตรรกะนั้น NULL จะเท่ากับ NULL ใด ๆ และ NULL ทั้งหมดนั้นแตกต่างกัน นี่ไม่ควรบอกเป็นนัยเลยว่า NULL ทั้งหมดนั้นไม่เหมือนใครและดัชนีที่ไม่ซ้ำกันควรอนุญาตให้มี NULL จำนวนเท่าใด?
คำตอบ:
ทำไมมันถึงทำงานแบบนี้? เพราะย้อนกลับไปเมื่อมีคนตัดสินใจการออกแบบโดยไม่ทราบหรือสนใจสิ่งที่มาตรฐานพูด (หลังจากทั้งหมดเรามีพฤติกรรมแปลก ๆ ทุกชนิดด้วยNULL
s และสามารถบีบบังคับพฤติกรรมที่แตกต่างได้ตามต้องการ) การตัดสินใจที่บอกว่าในนี้NULL = NULL
กรณี
มันไม่ใช่การตัดสินใจที่ฉลาดมาก สิ่งที่พวกเขาควรจะทำคือมีการทำงานเริ่มต้นกับมาตรฐาน ANSI ยึดมั่นและถ้าพวกเขาอยากพฤติกรรมที่แปลกประหลาดนี้จริงๆให้มันผ่านตัวเลือก DDL เหมือนหรือWITH CONSIDER_NULLS_EQUAL
WITH ALLOW_ONLY_ONE_NULL
แน่นอนว่าปัญหาย้อนหลังคือ 20/20
และเรามีวิธีแก้ไขปัญหาตอนนี้แม้ว่ามันจะไม่สะอาดหรือใช้งานง่ายที่สุด
คุณสามารถรับพฤติกรรม ANSI ที่เหมาะสมใน SQL Server 2008 และสูงกว่าได้โดยสร้างดัชนีที่ไม่ซ้ำกันและถูกกรอง
CREATE UNIQUE INDEX foo ON dbo.bar(key) WHERE key IS NOT NULL;
สิ่งนี้อนุญาตให้มีNULL
ค่ามากกว่าหนึ่งค่าได้เนื่องจากแถวเหล่านั้นไม่มีการตรวจสอบซ้ำ ในฐานะโบนัสที่เพิ่มเข้ามาสิ่งนี้จะกลายเป็นดัชนีที่เล็กกว่าที่ประกอบด้วยทั้งตารางหากNULL
อนุญาตให้มีหลายs (โดยเฉพาะเมื่อไม่ใช่คอลัมน์เดียวในดัชนีจะมีINCLUDE
คอลัมน์ ฯลฯ ) อย่างไรก็ตามคุณอาจต้องการทราบถึงข้อ จำกัด อื่น ๆ ของดัชนีที่ถูกกรอง:
แก้ไข. การใช้งานข้อ จำกัด หรือดัชนีที่ไม่ซ้ำกันในเซิร์ฟเวอร์ sql อนุญาตหนึ่ง NULL เดียว แก้ไขด้วยว่าเทคนิคนี้ไม่เหมาะกับคำจำกัดความของ NULL แต่เป็นหนึ่งในสิ่งที่พวกเขาทำเพื่อให้มีประโยชน์มากขึ้นแม้ว่าจะไม่ถูกต้อง "ทางเทคนิค" หมายเหตุคีย์หลัก (เช่นเดียวกับดัชนีที่ไม่ซ้ำกัน) ไม่อนุญาตให้ NULL (แน่นอน)
ก่อนอื่น - หยุดใช้วลี "ค่า Null" มันจะทำให้คุณหลงทาง ให้ใช้วลี "marker เป็นโมฆะ" - เครื่องหมายในคอลัมน์ที่ระบุว่าค่าจริงในคอลัมน์นี้อาจหายไปหรือไม่สามารถใช้งานได้ (แต่โปรดทราบว่าตัวทำเครื่องหมายไม่ได้พูดว่า
ทีนี้ลองนึกภาพต่อไปนี้ (โดยที่ฐานข้อมูลไม่มีความรู้ที่สมบูรณ์เกี่ยวกับสถานการณ์จำลอง)
Situation Database
ID Code ID Code
-- ----- -- -----
1 A 1 A
2 B 2 (null)
3 C 3 C
4 B 4 (null)
กฎความสมบูรณ์ที่เรากำลังสร้างแบบจำลองคือ "รหัสต้องไม่ซ้ำกัน" สถานการณ์ในโลกแห่งความจริงละเมิดสิ่งนี้ดังนั้นฐานข้อมูลไม่ควรอนุญาตให้ทั้งสองรายการและ 4 อยู่ในตารางในเวลาเดียวกัน
แนวทางที่ปลอดภัยที่สุดและยืดหยุ่นน้อยที่สุดคือการไม่อนุญาตให้ทำเครื่องหมายว่างในฟิลด์รหัสดังนั้นจึงไม่มีความเป็นไปได้ของข้อมูลที่ไม่สอดคล้องกัน วิธีการที่ยืดหยุ่นที่สุดคือการอนุญาตให้มีเครื่องหมายว่างหลายอันและกังวลเกี่ยวกับความเป็นเอกลักษณ์เมื่อป้อนค่า
ผู้เขียนโปรแกรม Sybase ใช้วิธีที่ค่อนข้างปลอดภัยและไม่ยืดหยุ่นมากเพียงอนุญาตให้มีเครื่องหมายว่างหนึ่งอันในตารางซึ่งมีผู้แสดงความคิดเห็นบางคนบ่นตั้งแต่นั้นเป็นต้นมา Microsoft ยังคงมีพฤติกรรมนี้ต่อไปฉันเดาว่าความเข้ากันได้ย้อนหลัง
¹ฉันแน่ใจว่าฉันอ่านที่ไหนสักแห่งที่ Codd พิจารณาว่าใช้เครื่องหมาย null สองอัน - อันหนึ่งไม่เป็นที่รู้จักหนึ่งอันไม่เหมาะสม - แต่ปฏิเสธ แต่ฉันไม่สามารถหาข้อมูลอ้างอิงได้ ฉันจำได้ถูกต้องหรือไม่
PS คำพูดที่ฉันชอบเกี่ยวกับ null: Louis Davidson, "การออกแบบฐานข้อมูล SQL Server 2000 Professional", Wrox Press, 2001, หน้า 52 "ต้มให้เป็นประโยคเดียว: NULL is evil"
null
ไม่บรรลุเป้าหมายนี้เช่นกัน เนื่องจากค่าที่หายไปอาจกลายเป็นค่าเดียวกับค่าหนึ่งในแถวอื่น
CHECK (Value IN ('A','B','C','D'))
? จากนั้นทั้งการดำเนินการของ SQL-Server และมาตรฐาน SQL อนุญาตให้ตารางมี 5 แถว (หนึ่งแถวสำหรับแต่ละค่าบวก 1 ด้วย NULL) จากนั้นเนื้อหาในขณะที่ฐานข้อมูลสอดคล้องกับข้อ จำกัด ของมันไม่สอดคล้องกับเจตนาของนักออกแบบสำหรับ ตารางมีได้สูงสุด 4 แถว ไม่มีค่าใด ๆ ที่ NULL สามารถเปลี่ยนเป็นที่จะไม่ละเมิดข้อ จำกัด เว้นแต่จะลบแถวตั้งแต่หนึ่งแถวขึ้นไป
CREATE TABLE #T(A INT NULL UNIQUE);INSERT INTO #T VALUES (1),(NULL);UPDATE #T SET A = 1 WHERE A IS NULL;
จะทำให้เกิดข้อผิดพลาด ตามทฤษฏีของคุณเกี่ยวกับแรงจูงใจในการออกแบบคุณควรป้องกันการแทรกNULL
ในกรณีแรก - เนื่องจากความรู้ที่ไม่สมบูรณ์หมายความว่าไม่มีการรับประกันว่ามูลค่าจะแตกต่างกัน
นี่อาจไม่ถูกต้องทางเทคนิค แต่ในทางปรัชญามันช่วยให้ฉันนอนหลับตอนกลางคืน ...
เช่นเดียวกับคนอื่น ๆ ที่พูดหรือพูดพาดพิงถึงถ้าคุณคิดว่าเป็นโมฆะไม่เป็นที่รู้จักแล้วคุณไม่สามารถกำหนดได้ว่าค่า NULL อันใดอันหนึ่งมีค่าเท่ากับค่า NULL อื่น ด้วยวิธีนี้นิพจน์ NULL == NULL ควรประเมินเป็น NULL ซึ่งไม่ทราบความหมาย
ข้อ จำกัด ที่ไม่ซ้ำกันจะต้องมีค่าที่ชัดเจนสำหรับการเปรียบเทียบค่าของคอลัมน์ กล่าวอีกนัยหนึ่งเมื่อเปรียบเทียบค่าคอลัมน์เดียวกับค่าคอลัมน์อื่น ๆ โดยใช้ตัวดำเนินการความเท่าเทียมกันจะต้องประเมินค่าเป็นเท็จให้ถูกต้อง ไม่รู้จักไม่จริงเท็จแม้ว่ามันมักจะถือว่าเป็นเท็จ ค่า NULL สองค่าอาจเท่ากันหรือไม่ ... มันไม่สามารถกำหนดได้อย่างแน่นอน
ช่วยให้คิดถึงข้อ จำกัด ที่ไม่เหมือนใครในการ จำกัด ค่าที่สามารถกำหนดให้แตกต่างจากกัน สิ่งที่ฉันหมายถึงคือถ้าคุณเรียกใช้ SELECT ที่มีลักษณะดังนี้:
SELECT * from dbo.table1 WHERE ColumnWithUniqueContraint="some value"
คนส่วนใหญ่คาดว่าจะมีผลลัพธ์เดียวเนื่องจากมีข้อ จำกัด ที่ไม่เหมือนใคร หากคุณอนุญาตให้มีค่า NULL หลายค่าใน ColumnWithUniqueConstraint คุณจะไม่สามารถเลือกแถวที่แตกต่างจากตารางโดยใช้ค่า NULL เป็นค่าที่เปรียบเทียบได้
จากการที่ฉันเชื่อว่าไม่ว่ามันจะถูกนำไปใช้อย่างถูกต้องตามคำจำกัดความของ NULL หรือไม่ก็ตามมันมีประโยชน์มากกว่าในหลายสถานการณ์
หนึ่งในวัตถุประสงค์หลักของUNIQUE
ข้อ จำกัด คือการป้องกันการบันทึกที่ซ้ำกัน หากจำเป็นต้องมีตารางซึ่งอาจมีหลายระเบียนที่ค่าเป็น "ไม่ทราบ" แต่ไม่มีสองระเบียนที่ได้รับอนุญาตให้มีค่า "รู้จัก" เหมือนกันดังนั้นค่าที่ไม่รู้จักควรได้รับการกำหนดค่าตัวระบุที่ไม่ซ้ำกันก่อนที่จะ เพิ่มลงในตารางแล้ว
มีบางกรณีที่หายากไม่กี่รายที่คอลัมน์ซึ่งมีUNIQUE
ข้อ จำกัด และมีค่า Null เพียงค่าเดียว ตัวอย่างเช่นถ้าตารางมีการทำแผนที่ระหว่างค่าของคอลัมน์และคำอธิบายข้อความที่แปลภาษา, แถวที่NULL
จะทำให้มันเป็นไปได้ที่จะกำหนดรายละเอียดที่ควรจะปรากฏขึ้นเมื่อคอลัมน์ในตารางอื่น ๆ NULL
บางอย่างคือ พฤติกรรมของการNULL
อนุญาตสำหรับกรณีการใช้งานที่
มิฉะนั้นฉันไม่เห็นพื้นฐานสำหรับฐานข้อมูลที่มีUNIQUE
ข้อ จำกัด ในคอลัมน์ใด ๆ เพื่ออนุญาตการมีอยู่ของระเบียนที่เหมือนกันจำนวนมาก แต่ฉันไม่เห็นวิธีการป้องกันในขณะที่อนุญาตให้มีหลายระเบียนที่ค่าคีย์ไม่สามารถแยกแยะได้ การประกาศที่NULL
ไม่เท่ากับตัวเองจะไม่ทำให้NULL
คุณค่าแตกต่างกัน