หนึ่งในกับดักที่นักพัฒนา SQL ทั้งมือใหม่และมือเก๋าอาจเคยเจอ คือการที่ผลลัพธ์จากการคิวรี่ไม่เป็นไปตามที่คาดหวัง โดยเฉพาะเมื่อต้องจัดการกับคอลัมน์ที่มีค่า NULL
ลองจินตนาการถึงสถานการณ์นี้
เรามีตารางชื่อ orders
ที่เก็บข้อมูลคำสั่งซื้อสินค้า และมีคอลัมน์ shipped_date
เพื่อบอกวันที่สินค้าถูกจัดส่ง ถ้า shipped_date
เป็น NULL
แสดงว่าสินค้านั้นยังไม่ถูกจัดส่ง
ตาราง orders
order_id | product_name | customer_id | shipped_date |
---|---|---|---|
101 | Keyboard | 12 | 2025-07-10 |
102 | Mouse | 15 | 2025-07-11 |
103 | Monitor | 12 | NULL |
104 | Webcam | 21 | 2025-07-11 |
105 | USB Hub | 15 | NULL |
สมมติว่าเราต้องการหารายการสั่งซื้อทั้งหมดที่ ไม่ได้ถูกจัดส่งในวันที่ 2025-07-11
โดยเราอาจจะเขียนคิวรี่ง่ายๆ แบบนี้:
เราคาดหวังว่าจะได้ผลลัพธ์ 3 แถว คือ order_id
101 (ส่งวันอื่น), 103 (ยังไม่ส่ง) และ 105 (ยังไม่ส่ง) แต่ผลลัพธ์ที่ได้กลับมามีเพียงแถวเดียว:
order_id | product_name | shipped_date |
---|---|---|
101 | Keyboard | 2025-07-10 |
เกิดอะไรขึ้น? ทำไมรายการที่ยังไม่ถูกส่ง (shipped_date
เป็น NULL
) ถึงหายไป?
หัวใจของปัญหานี้คือความเข้าใจผิดเกี่ยวกับ NULL
ในโลกของฐานข้อมูล NULL
ไม่ใช่ค่าที่เท่ากับ 0, ไม่ใช่ช่องว่าง, และไม่ใช่ "ไม่มีอะไร" แต่มันคือ สถานะ (state) ที่บ่งบอกว่า "ไม่ทราบค่า" (unknown) หรือ "ไม่มีข้อมูล" (missing value)
ด้วยเหตุนี้ ระบบจัดการฐานข้อมูลจึงใช้ตรรกะแบบสามค่า (Three-Valued Logic หรือ 3VL) ซึ่งประกอบด้วย:
เมื่อคุณนำ NULL
ไปเปรียบเทียบกับค่าใดๆ ด้วยโอเปอเรเตอร์ทางตรรกะ (=
, !=
, <
, >
) ผลลัพธ์ที่ได้จะเป็น UNKNOWN
เสมอ
เงื่อนไข WHERE
ใน SQL จะดึงข้อมูลเฉพาะแถวที่ผลลัพธ์ของเงื่อนไขเป็น TRUE
เท่านั้น มันจะทิ้งแถวที่ผลลัพธ์เป็น FALSE
และ UNKNOWN
ไปทั้งหมด นี่คือสาเหตุที่แถว order_id
103 และ 105 หายไปจากผลลัพธ์ของเรา
วิธีแก้ไข: จัดการ NULL อย่างชัดเจน
เพื่อให้ได้ผลลัพธ์ตามที่ต้องการ เราต้องเขียนเงื่อนไขเพื่อจัดการกับ NULL
โดยเฉพาะ เป็นวิธีที่ตรงไปตรงมาที่สุด คือการเพิ่มเงื่อนไขเข้าไปว่า "หรือค่าในคอลัมน์นั้นต้องเป็น NULL"
ผลลัพธ์ที่ถูกต้อง:
order_id | product_name | shipped_date |
---|---|---|
101 | Keyboard | 2025-07-10 |
103 | Monitor | NULL |
105 | USB Hub | NULL |
ตอนนี้คิวรี่ทำงานถูกต้องแล้ว เพราะมันเลือกแถวที่ shipped_date
ไม่ใช่วันที่ '2025-07-11' หรือ แถวที่ shipped_date
เป็น NULL
วิธีที่ 2: ใช้ฟังก์ชัน COALESCE
COALESCE
เป็นฟังก์ชันที่มีประโยชน์มากในการจัดการ NULL
มันจะคืนค่าแรกที่ไม่ใช่ NULL
จากรายการที่เราส่งเข้าไป เราสามารถใช้มันเพื่อแปลง NULL
ให้เป็นค่าอื่นชั่วคราวเพื่อการเปรียบเทียบได้
ในคิวรี่นี้ ถ้า shipped_date เป็น NULL มันจะถูกแทนที่ด้วยวันที่ '1900-01-01' ก่อนนำไปเปรียบเทียบ ทำให้เงื่อนไข '1900-01-01' != '2025-07-11' เป็น TRUE และได้ผลลัพธ์ที่ถูกต้องเช่นกัน