ทำความเข้าใจเรื่อง Foreign Key ใน MySQL
Sirichai Teerapattarasakul / May 20, 2025
2 min read
ทำงานกับฐานข้อมูล (Database) วันนี้เลยอยากมาแชร์เรื่อง Foreign Key กันหน่อย เพราะเป็นเรื่องที่เจอบ่อยแต่บางทีก็ยังสับสนกันอยู่ครับ
Foreign Key คืออะไร?
ง่ายๆ เลยนะครับ Foreign Key ก็เหมือนกับการเชื่อมโยงข้อมูลระหว่างตาราง 2 ตารางเข้าด้วยกัน เพื่อให้ข้อมูลมีความสัมพันธ์กัน และที่สำคัญ คือ รักษาความถูกต้องของข้อมูล หรือที่เรียกว่า Referential Integrity นั่นเอง
ยกตัวอย่างแบบบ้านๆ เลยนะครับ เหมือนเราเป็นร้านค้าที่มี 2 ตาราง:
- ตารางลูกค้า (ตารางแม่)
- ตารางสั่งซื้อ (ตารางลูก)
ผมจะไม่อยากให้มีการสั่งซื้อที่ไม่มีลูกค้าใช่ไหมครับ เพราะจะเกิดคำถามว่า "แล้วส่งของให้ใครล่ะ?" นี่แหละครับ คือประโยชน์ของ Foreign Key
ON DELETE และ ON UPDATE คืออะไร?
ถ้าเราเคยทำงานกับฐานข้อมูลจริงๆ ก็จะรู้ว่าชีวิตไม่ได้หยุดนิ่ง ข้อมูลมีการเปลี่ยนแปลงตลอดเวลา:
- ลูกค้าอาจจะยกเลิกการเป็นสมาชิก (ลบข้อมูล)
- ลูกค้าอาจจะขอเปลี่ยนรหัสลูกค้า (อัพเดตข้อมูล)
แล้วคำถามคือ ถ้าข้อมูลในตารางแม่เปลี่ยน แล้วข้อมูลในตารางลูกล่ะ จะทำยังไง? เนี่ยแหละครับคือจุดที่ ON DELETE
และ ON UPDATE
เข้ามาช่วย
ผมขอเล่าจากประสบการณ์จริงนะครับ เมื่อก่อนตอนที่ผมยังไม่เข้าใจเรื่องนี้ เคยลบข้อมูลลูกค้าไปแล้วต้องมานั่งแก้ปัญหาข้อมูลการสั่งซื้อที่ไม่มีลูกค้าอยู่หลายชั่วโมง เพราะไม่ได้กำหนด ON DELETE ไว้... โดนหัวหน้าดุเลย 😅
ตัวเลือกใน ON DELETE และ ON UPDATE มีอะไรบ้าง?
MySQL มีตัวเลือกให้เราใช้ 5 แบบ ซึ่งแต่ละแบบก็เหมาะกับสถานการณ์ต่างกัน:
1. CASCADE
นี่เป็นแบบที่ผมใช้บ่อยสุดครับ เพราะง่ายดี คือ ถ้าแม่เปลี่ยน ลูกก็เปลี่ยนตาม
- ลบลูกค้า = ลบการสั่งซื้อทั้งหมดของลูกค้านั้น
- แก้ไขรหัสลูกค้า = แก้ไขรหัสลูกค้าในทุกการสั่งซื้อของลูกค้านั้น
2. SET NULL
ตัวนี้จะ เปลี่ยนค่าในตารางลูกให้เป็น NULL แทน เหมาะกับกรณีที่ต้องการเก็บประวัติไว้ แต่ไม่ต้องการระบุว่าเป็นของใคร
- ผมเคยใช้กับระบบบล็อกที่ถ้าลบผู้ใช้ไป โพสต์ทั้งหมดก็จะกลายเป็นโพสต์ไม่ระบุตัวตน (แต่ต้องยอมให้ฟิลด์เป็น NULL ได้นะครับ)
3. SET DEFAULT
ตั้งค่าให้เป็นค่าเริ่มต้น (default) แทน ถ้าเราตั้งค่า default ไว้ล่วงหน้า
- ยกตัวอย่างเช่น เราอาจตั้งรหัสลูกค้าเริ่มต้นเป็น '0' (ลูกค้าทั่วไป) อะไรแบบนี้
4. RESTRICT และ 5. NO ACTION
สองตัวนี้ใน MySQL จะทำงานเหมือนกันเลย คือ ห้ามลบหรือแก้ไขข้อมูลในตารางแม่ ถ้ายังมีการอ้างอิงในตารางลูกอยู่
- ผมมักใช้ตัวนี้กับข้อมูลสำคัญที่ต้องการป้องกันไม่ให้ลบผิดพลาด เช่น ถ้าจะลบลูกค้า ต้องไปลบการสั่งซื้อของลูกค้านั้นให้หมดก่อน
ตัวอย่างการใช้งานจริง
จากประสบการณ์ทำงานจริงๆ ผมขอยกตัวอย่างการสร้าง Foreign Key แบบนี้ครับ:
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
total_amount DECIMAL(10,2),
CONSTRAINT fk_customer
FOREIGN KEY (customer_id)
REFERENCES customers(customer_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
จากโค้ดข้างบน:
- ถ้าเราลบลูกค้าคนไหน ออเดอร์ทั้งหมดของลูกค้าคนนั้นก็จะหายไปด้วย (ON DELETE CASCADE)
- ถ้าเราเปลี่ยนรหัสลูกค้า รหัสในตารางออเดอร์ก็จะเปลี่ยนตามโดยอัตโนมัติ (ON UPDATE CASCADE)
ผมมักจะตั้งชื่อ constraint ด้วย (fk_customer) เพื่อให้ระบุได้ง่ายเวลามีปัญหาครับ
ประสบการณ์จริงและข้อควรระวัง
ผมเคยเจอหลายเคสจากการพัฒนาระบบ เช่น:
เคสเลือกใช้ CASCADE แล้วลืมไป - ทำให้ลบข้อมูลมากกว่าที่ตั้งใจ ถ้าเราลบข้อมูลในตารางแม่ไป ข้อมูลเชื่อมโยงในตารางลูกก็จะหายไปด้วย เคยมีครั้งหนึ่งลบข้อมูลบริษัทตัวแทนขายไปแค่บริษัทเดียว แต่กลับเกิดการลบข้อมูลคำสั่งซื้อกว่าสามพันรายการ! (ดีที่มี backup ไว้)
เลือกใช้ SET NULL แต่ลืมให้ฟิลด์รับ NULL - MySQL จะแจ้ง Error เวลาสร้าง Foreign Key ว่า field ต้องรับค่า NULL ได้ พอไปแก้ก็ต้องมาปรับโครงสร้างใหม่หมด
ใช้ CHECK VERSION - ถ้าใช้ MySQL เวอร์ชันเก่ากว่า 8.0 SET DEFAULT จะยังใช้ไม่ได้จริงๆ (มีแต่ไวยากรณ์แต่ไม่ได้ทำงาน)
ปิดท้าย - สรุปว่าควรใช้อันไหนดี?
จากประสบการณ์ผมนะครับ:
- CASCADE - เหมาะกับข้อมูลที่ "เป็นของ" กันและกัน เช่น ออเดอร์เป็นของลูกค้า, โพสต์เป็นของบล็อก
- SET NULL - เหมาะกับข้อมูลที่อยากเก็บประวัติไว้แม้ตัวหลักจะหายไป
- RESTRICT/NO ACTION - เหมาะกับข้อมูลสำคัญที่ต้องมั่นใจว่าจะไม่มีการลบผิดพลาด
สุดท้ายอย่าลืมนะครับว่า ตารางที่ใช้ Foreign Key ต้องเป็นชนิด InnoDB เท่านั้น! อันนี้ผมเคยเจอปัญหาตอนเริ่มทำงานใหม่ๆ สงสัยว่าทำไม Foreign Key ไม่ทำงาน ที่แท้เป็นเพราะตารางเป็น MyISAM อยู่...
หวังว่าบทความนี้จะช่วยให้ทุกคนเข้าใจ Foreign Key ง่ายขึ้นนะครับ