ทำความเข้าใจเรื่อง Foreign Key ใน MySQL

Sirichai Teerapattarasakul

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) เพื่อให้ระบุได้ง่ายเวลามีปัญหาครับ

ประสบการณ์จริงและข้อควรระวัง

ผมเคยเจอหลายเคสจากการพัฒนาระบบ เช่น:

  1. เคสเลือกใช้ CASCADE แล้วลืมไป - ทำให้ลบข้อมูลมากกว่าที่ตั้งใจ ถ้าเราลบข้อมูลในตารางแม่ไป ข้อมูลเชื่อมโยงในตารางลูกก็จะหายไปด้วย เคยมีครั้งหนึ่งลบข้อมูลบริษัทตัวแทนขายไปแค่บริษัทเดียว แต่กลับเกิดการลบข้อมูลคำสั่งซื้อกว่าสามพันรายการ! (ดีที่มี backup ไว้)

  2. เลือกใช้ SET NULL แต่ลืมให้ฟิลด์รับ NULL - MySQL จะแจ้ง Error เวลาสร้าง Foreign Key ว่า field ต้องรับค่า NULL ได้ พอไปแก้ก็ต้องมาปรับโครงสร้างใหม่หมด

  3. ใช้ CHECK VERSION - ถ้าใช้ MySQL เวอร์ชันเก่ากว่า 8.0 SET DEFAULT จะยังใช้ไม่ได้จริงๆ (มีแต่ไวยากรณ์แต่ไม่ได้ทำงาน)

ปิดท้าย - สรุปว่าควรใช้อันไหนดี?

จากประสบการณ์ผมนะครับ:

  • CASCADE - เหมาะกับข้อมูลที่ "เป็นของ" กันและกัน เช่น ออเดอร์เป็นของลูกค้า, โพสต์เป็นของบล็อก
  • SET NULL - เหมาะกับข้อมูลที่อยากเก็บประวัติไว้แม้ตัวหลักจะหายไป
  • RESTRICT/NO ACTION - เหมาะกับข้อมูลสำคัญที่ต้องมั่นใจว่าจะไม่มีการลบผิดพลาด

สุดท้ายอย่าลืมนะครับว่า ตารางที่ใช้ Foreign Key ต้องเป็นชนิด InnoDB เท่านั้น! อันนี้ผมเคยเจอปัญหาตอนเริ่มทำงานใหม่ๆ สงสัยว่าทำไม Foreign Key ไม่ทำงาน ที่แท้เป็นเพราะตารางเป็น MyISAM อยู่...

หวังว่าบทความนี้จะช่วยให้ทุกคนเข้าใจ Foreign Key ง่ายขึ้นนะครับ