PlusMagi's Blog By Pitt Phunsanit Backend,Database ออกแบบความสัมพันธ์ 1:1, 1:N และ N:M: วิธีออกแบบตารางและการใช้ Junction Table

ออกแบบความสัมพันธ์ 1:1, 1:N และ N:M: วิธีออกแบบตารางและการใช้ Junction Table

ในฐานะ Senior Architect การออกแบบฐานข้อมูล (Database Schema) ที่แข็งแกร่งคือรากฐานของระบบซอฟต์แวร์ที่ยั่งยืน ข้อมูลในโลกจริงไม่ได้ดำรงอยู่โดดเดี่ยว แต่มีความสัมพันธ์ที่ซับซ้อน การทำความเข้าใจและนำรูปแบบความสัมพันธ์ (Relationships) ต่างๆ มาประยุกต์ใช้ได้อย่างถูกต้องจึงเป็นทักษะที่สำคัญที่สุดในการเป็นนักพัฒนาระบบ

บทความนี้จะเจาะลึกหลักการออกแบบความสัมพันธ์หลัก 3 รูปแบบ คือ One-to-One (1:1), One-to-Many (1:N), และ Many-to-Many (N:M) พร้อมสาธิตการใช้งานจริงด้วยไวยากรณ์ของ PostgreSQL เพื่อให้คุณสามารถสร้างโครงสร้างข้อมูลที่ถูกต้องและมีประสิทธิภาพสูงสุด

1. ความสัมพันธ์แบบหนึ่งต่อหนึ่ง (One-to-One: 1:1)

ความสัมพันธ์ 1:1 คือการที่เอนทิตี้สองตัวมีความเชื่อมโยงกันแบบหนึ่งต่อหนึ่งเท่านั้น ตัวอย่างเช่น ข้อมูลผู้ใช้งานหลัก (Users) กับข้อมูลโปรไฟล์ส่วนตัวที่ละเอียดอ่อน (User_Profile) ซึ่งเราอาจต้องการแยกเก็บไว้เพื่อลดความซ้ำซ้อนและเพิ่มความยืดหยุ่นในการอัปเดต

หลักการออกแบบ: ใช้ Foreign Key (FK) ในตารางรอง และต้องกำหนดให้ FK นั้นมีข้อจำกัด (Constraint) เป็น UNIQUE เพื่อรับประกันว่าค่าในคอลัมน์นั้นไม่ซ้ำกัน

2. ความสัมพันธ์แบบหนึ่งต่อกลุ่ม (One-to-Many: 1:N)

ความสัมพันธ์ 1:N เป็นรูปแบบที่พบได้บ่อยที่สุด ตัวอย่างเช่น ลูกค้า (Customers) หนึ่งรายสามารถมีคำสั่งซื้อ (Orders) ได้หลายรายการ

หลักการออกแบบ: นำ Foreign Key ไปวางไว้ที่ตารางฝั่ง ‘N’ (ตารางที่มีหลายรายการ) เพื่ออ้างอิงถึง Primary Key ของตารางฝั่ง ‘1’

3. ความสัมพันธ์แบบกลุ่มต่อกลุ่ม (Many-to-Many: N:M) และ Junction Table

ความสัมพันธ์ N:M คือความซับซ้อนที่สุดและสำคัญที่สุด ตัวอย่างเช่น นักเรียน (Students) หนึ่งคนสามารถลงทะเบียนเรียนได้หลายวิชา (Courses) และในทางกลับกัน วิชาหนึ่งก็มีนักเรียนหลายคนลงทะเบียนได้

ปัญหา: หากพยายามเก็บความสัมพันธ์นี้ในตารางใดตารางหนึ่ง จะเกิด Data Redundancy อย่างรุนแรง

แนวทางแก้ไข (The Solution): เราต้องใช้ตารางตัวกลาง (Junction Table หรือ Linking Table) เพื่อทำหน้าที่เป็นสะพานเชื่อม ตารางนี้จะเก็บ Foreign Keys ของเอนทิตี้ทั้งสองฝั่ง และ Primary Key ของ Junction Table มักจะเป็น Composite Key ที่ประกอบด้วย FK ทั้งสองตัว

ตัวอย่างการออกแบบด้วย PostgreSQL

นี่คือตัวอย่างโค้ด SQL สำหรับการออกแบบทั้งสามรูปแบบ:

SQL

-- 1. One-to-One (Users <-> User_Profile) --
CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL
);

CREATE TABLE user_profile (
    user_id INT PRIMARY KEY REFERENCES users(user_id),
    bio TEXT,
    phone_number VARCHAR(15) UNIQUE -- ต้องมี UNIQUE constraint
);

-- 2. One-to-Many (Customers -> Orders) --
CREATE TABLE customers (
    customer_id SERIAL PRIMARY KEY,
    name VARCHAR(100)
);

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer_id INT REFERENCES customers(customer_id),
    order_date DATE
);

-- 3. Many-to-Many (Students <-> Courses) --
CREATE TABLE students (
    student_id SERIAL PRIMARY KEY,
    student_name VARCHAR(100)
);

CREATE TABLE courses (
    course_id SERIAL PRIMARY KEY,
    course_name VARCHAR(100)
);

CREATE TABLE enrollment (
    student_id INT REFERENCES students(student_id),
    course_id INT REFERENCES courses(course_id),
    enrollment_date DATE,
    PRIMARY KEY (student_id, course_id) -- Composite Key
);

บทสรุปสำหรับสถาปนิกระบบ

การออกแบบความสัมพันธ์ที่ถูกต้องเป็นสิ่งสำคัญที่กำหนดประสิทธิภาพและความสามารถในการขยายตัว (Scalability) ของระบบ เมื่อคุณเผชิญกับความสัมพันธ์ N:M อย่าลืมใช้ Junction Table เสมอ และเมื่อคุณต้องการแยกข้อมูลที่เกี่ยวข้องแต่ไม่จำเป็นต้องเรียกใช้พร้อมกัน ให้พิจารณาใช้ 1:1 เพื่อรักษาความสมบูรณ์ของข้อมูล (Data Integrity) การทำความเข้าใจหลักการเหล่านี้จะช่วยให้คุณสร้าง Schema ฐานข้อมูลที่แข็งแกร่ง ทนทาน และพร้อมรองรับการเติบโตในอนาคตได้อย่างแท้จริง