4 คะแนน โดย GN⁺ 2025-01-11 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • ใน SQL ค่า NULL ถูกจัดการอย่างมีลักษณะเฉพาะ คอลัมน์ที่มีข้อจำกัด UNIQUE สามารถมีค่า NULL ได้หลายค่า

    • เพราะค่า NULL แต่ละค่าถูกมองว่าเป็นค่าอิสระที่แตกต่างจาก NULL ตัวอื่น
    • SQLite, Postgres และ MySQL ล้วนทำงานแบบเดียวกัน
  • การตั้งเกณฑ์

    select '' = '';    -- Returns 1 (true) สตริงว่างเท่ากัน   
    select 1 = 1;      -- Returns 1 (true) ตัวเลขเท่ากัน   
    select 1 = 0;      -- Returns 0 (false) ตัวเลขไม่เท่ากัน   
    select null = null; -- Returns NULL (null) อ้าว?  
    
    • เนื่องจาก NULL เป็นตัวแทนของ "ค่าที่ไม่ทราบ" จึงถือว่าค่าที่ไม่ทราบสองค่านั้นไม่จำเป็นต้องเท่ากัน
    • หากใช้ตัวดำเนินการ IS จะสามารถตรวจสอบอัตลักษณ์ของ NULL ได้ เช่น null is null จะคืนค่า TRUE
  • เรื่องของความเป็นเอกลักษณ์

    • เมื่อคอลัมน์ที่มีข้อจำกัด UNIQUE มีค่า NULL อยู่ ค่า NULL จะถือว่าแตกต่างกัน จึงไม่ละเมิดข้อจำกัดความเป็นเอกลักษณ์
    • ตัวอย่างเช่น ('ray@mail.com', NULL) กับ ('ray@mail.com', NULL) จะถูกมองว่าเป็นคนละแถว
  • ทำไม NULL ถึงถูกจัดการแบบนี้

    • SQLite และฐานข้อมูล SQL-compatible อื่น ๆ ถูกออกแบบมาแบบนี้เพื่อให้จัดการ NULL ได้สอดคล้องกับฐานข้อมูลอื่น ๆ เอกสารมาตรฐาน SQL เสนอว่า NULL ควรมีความเป็นเอกลักษณ์ทุกที่ แต่ในทางปฏิบัติ SQL engine ส่วนใหญ่ไม่ได้จัดการ NULL แบบเป็นค่าเฉพาะใน SELECT DISTINCT หรือ UNION
  • วิธีรับประกันความเป็นเอกลักษณ์

    • ใช้ generated column

      • สามารถบรรเทาปัญหาได้ด้วยการสร้างคอลัมน์ที่มีค่ากำหนดแน่นอนและไม่เป็น NULL เสมอ เช่น ใช้ COALESCE(deleted_at, '1970-01-01') เพื่อแทนค่า NULL
      • วิธีนี้อาจใช้พื้นที่เพิ่ม เพราะเป็นการเพิ่มฟิลด์เข้าไปในตาราง
    • ใช้ partial index

      • สามารถรับประกันความเป็นเอกลักษณ์ได้ด้วยการสร้าง partial index สำหรับ email เฉพาะกรณีที่ deleted_at เป็น NULL
      • partial index ไม่ทำให้ตารางกว้างขึ้น ใช้พื้นที่น้อยกว่า และจะไม่เกิดข้อผิดพลาดเมื่อมีการลบเรคคอร์ดคู่เดิมซ้ำ ๆ
  • อัปเดต

    • Oracle จัดการสตริงว่างเป็น NULL
  • สรุป

    • แม้จะมองไม่เห็นเมื่อใช้ ORM แต่ลักษณะการจัดการ NULL อันเป็นเอกลักษณ์ของ SQL อาจทำให้สับสนได้ เอกสารมาตรฐาน SQL ไม่ได้เปิดเผยสาธารณะ และต้องจ่ายเงินจึงจะเข้าถึงได้

2 ความคิดเห็น

 
iolothebard 2025-01-14

null ทุกแบบล้วนประหลาดทั้งนั้น
ดังนั้น null ของ SQL ที่จริง ๆ ก็ปกติดี เลยกลับดูเหมือนแปลกไปเสียอย่างนั้น…
ในดินแดนของคนตาเดียว คนสองตากลับกลายเป็นคนผิดปกติ…

 
GN⁺ 2025-01-11
ความเห็นจาก Hacker News
  • NULL ใน SQL มีพื้นฐานมาจากตรรกะ TRUE-FALSE-UNKNOWN ของ Kleene ถ้าอ่าน NULL เป็น UNKNOWN จะเข้าใจการดำเนินการหลายอย่างได้อย่างเป็นธรรมชาติมากขึ้น

    • TRUE OR UNKNOWN = TRUE, TRUE AND UNKNOWN = UNKNOWN, UNKNOWN XOR UNKNOWN = UNKNOWN เป็นต้น
    • NULL เป็นตัวแทนที่ใช้สื่อถึง UNKNOWN และไม่อาจกล่าวได้ว่า NULL สองค่ามีค่าเท่ากัน
    • ตั้งแต่ PostgreSQL 15 เป็นต้นไป สามารถใช้ NULLS NOT DISTINCT เพื่อสร้าง unique index ได้
  • ตอนที่แนวคิดเรื่อง NULL ถูกนำเข้ามาในทศวรรษ 1970 ก็คิดไว้แล้วว่าในอนาคตมันจะทำให้เกิดความสับสนมากมาย ผ่านมา 45 ปี ทุกวันนี้ก็ยังคงถกเถียงกันอยู่

  • วิธีทำความเข้าใจ NULL แบบตรงไปตรงมา: ค่า NULL ในเซลล์หนึ่งของตารางคือวิธีแสดงว่า "ไม่มีค่า" เมื่อคุณต้องการค่าที่ไม่ซ้ำกัน กรณีที่ไม่มีค่าก็ไม่ควรถูกนำมาพิจารณา

  • ความกังขาต่อการใช้ ORM: ORM สะดวกก็จริง แต่ทำให้เกิดคนรุ่นหนึ่งที่ไม่เคยเรียนรู้ว่าฐานข้อมูลเชิงสัมพันธ์ทำงานจริงอย่างไร พฤติกรรมของ SQL NULL สอดคล้องกับ relational algebra พื้นฐาน และ NULL แบบสไตล์ C ต่างหากที่เป็นปัญหา

  • ทำให้นึกถึงมุกเกี่ยวกับการเปรียบเทียบ NULL ในบทสนทนาจากตอนหนึ่งของ Blackadder

  • คิดว่าเป็นเรื่องแปลกที่ใน Oracle NULL เท่ากับสตริงว่าง

  • ในบริบทเชิงวัตถุ null มีประโยชน์ในการสื่อว่าแอตทริบิวต์หนึ่งไม่มีค่า ใน JavaScript มีทั้ง null และ undefined ซึ่งอาจมองได้ว่า undefined คือไม่รู้ค่า ส่วน null คือไม่มีค่า

  • NULL ไม่ได้แปลกในแง่ของการไม่มีค่าซ้ำ เพราะ NULL ไม่เท่ากันเอง จึงไม่อาจถือเป็นค่าซ้ำได้ ถ้าไม่ชอบความหมายเชิงตรรกะของ NULL ก็สามารถใช้ sentinel value ได้

  • SQL NULL จะไม่ดูแปลกเลย หากพิจารณาว่าคุณต้องการให้ตรรกะเชิงสัมพันธ์ทำงานอย่างไรกับเรคอร์ดที่มีค่าซึ่งไม่มีอยู่จริง