CodeGym /Các khóa học /SQL SELF /Mô hình hóa quan hệ MANY-TO-MANY bằng bảng trung gian

Mô hình hóa quan hệ MANY-TO-MANY bằng bảng trung gian

SQL SELF
Mức độ , Bài học
Có sẵn

Quan hệ "nhiều-nhiều" là khi một bản ghi trong một bảng có thể liên kết với nhiều bản ghi ở bảng khác, và ngược lại. Ví dụ: - Một sinh viên (từ bảng students) có thể đăng ký nhiều khóa học (từ bảng courses). - Một khóa học có thể có nhiều sinh viên tham gia.

Vấn đề là lưu trữ trực tiếp kiểu quan hệ này rất bất tiện. Vì vậy, bảng trung gian sẽ giúp ta lưu các liên kết này.

Ví dụ thực tế

Giả sử bạn tạo một bảng sinh viên và một bảng khóa học. Nếu bạn cố thêm vào mỗi bảng một cột để lưu tất cả dữ liệu liên quan, sẽ rất rối:

  • Trong bảng students bạn sẽ phải lưu danh sách tất cả các khóa học mà sinh viên đăng ký. Nhưng lưu danh sách kiểu gì? Dùng dấu phẩy? Dùng mảng? Rất khó để truy vấn.
  • Trong bảng courses bạn sẽ phải lưu danh sách sinh viên, và điều này thực sự đau đầu luôn.

Vì vậy, giải pháp đúng là tạo thêm một bảng thứ ba để lưu các liên kết giữa sinh viên và khóa học.

Bảng trung gian: cứu tinh của chúng ta!

Bảng trung gian (còn gọi là bảng liên kết) giải quyết mọi vấn đề. Nó chứa hai khóa ngoại:

  • Khóa ngoại trỏ đến bảng students.
  • Khóa ngoại trỏ đến bảng courses.

Mỗi bản ghi trong bảng này tạo ra một liên kết giữa một sinh viên cụ thể và một khóa học cụ thể.

Tạo bảng cho quan hệ "nhiều-nhiều"

Cùng thực hành nhé! Đây là cách tạo bảng để liên kết sinh viên và khóa học:

Bước 1: Tạo bảng students

Đây là bảng sinh viên của chúng ta. Ở đây ta lưu id duy nhất của sinh viên và tên của họ.

CREATE TABLE students (
    student_id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);
  • student_id — id duy nhất của sinh viên (tự tăng, cảm ơn SERIAL!).
  • name — tên sinh viên.

Bước 2: Tạo bảng courses

Bây giờ tạo bảng cho khóa học. Ở đây ta lưu id duy nhất của khóa học và tên của nó.

CREATE TABLE courses (
    course_id SERIAL PRIMARY KEY,
    title TEXT NOT NULL
);
  • course_id — id duy nhất của khóa học.
  • title — tên khóa học.

Bước 3: Tạo bảng trung gian enrollments

Bây giờ tạo bảng liên kết thần thánh của chúng ta. Nó có hai cột, mỗi cột là một khóa ngoại trỏ đến các bảng tương ứng.

CREATE TABLE enrollments (
    student_id INT REFERENCES students(student_id),
    course_id INT REFERENCES courses(course_id),
    PRIMARY KEY (student_id, course_id)
);

Phân tích cấu trúc:

  • student_id — khóa ngoại trỏ đến student_id của bảng students.
  • course_id — khóa ngoại trỏ đến course_id của bảng courses.
  • PRIMARY KEY (student_id, course_id) — khóa chính là sự kết hợp của hai khóa ngoại. Điều này đảm bảo mỗi liên kết là duy nhất.

Chèn dữ liệu

Thêm chút dữ liệu để test xem mọi thứ hoạt động thế nào nhé.

Bước 1: Thêm sinh viên

INSERT INTO students (name) VALUES
('Alice'),
('Bob'),
('Charlie');

Kết quả:

student_id name
1 Alice
2 Bob
3 Charlie

Bước 2: Thêm khóa học

INSERT INTO courses (title) VALUES
('Mathematics'),
('History'),
('Biology');

Kết quả:

course_id title
1 Mathematics
2 History
3 Biology

Bước 3: Thêm bản ghi vào enrollments

Bây giờ đăng ký sinh viên vào các khóa học. Ví dụ:

  • Alice đăng ký MathematicsHistory.
  • Bob chỉ đăng ký Biology.
  • Charlie đăng ký cả ba khóa học.
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 1), -- Alice đăng ký Mathematics
(1, 2), -- Alice đăng ký History
(2, 3), -- Bob đăng ký Biology
(3, 1), -- Charlie đăng ký Mathematics
(3, 2), -- Charlie đăng ký History
(3, 3); -- Charlie đăng ký Biology

Kết quả:

student_id course_id
1 1
1 2
2 3
3 1
3 2
3 3

Truy vấn cho quan hệ "nhiều-nhiều"

Bây giờ có dữ liệu rồi, cùng tận dụng nó nhé!

Làm sao tìm tất cả các khóa học mà một sinh viên đã đăng ký?

Ví dụ, để biết Alice (ID = 1) đã đăng ký những khóa nào, chạy truy vấn này:

SELECT c.title
FROM courses c
JOIN enrollments e ON c.course_id = e.course_id
WHERE e.student_id = 1;

Kết quả:

title
Mathematics
History

Làm sao tìm tất cả sinh viên đã đăng ký một khóa học cụ thể?

Giả sử muốn biết ai đã đăng ký khóa Mathematics (ID = 1):

SELECT s.name
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
WHERE e.course_id = 1;

Kết quả:

name
Alice
Charlie

Làm sao tìm sinh viên và các khóa học của họ?

Để xem tổng thể ai đăng ký gì, chạy truy vấn này:

SELECT s.name AS student, c.title AS course
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
JOIN courses c ON e.course_id = c.course_id;

Kết quả:

student course
Alice Mathematics
Alice History
Bob Biology
Charlie Mathematics
Charlie History
Charlie Biology

Bảng enrollments làm cho schema của ta cực kỳ linh hoạt — có thể thêm/xóa liên kết giữa sinh viên và khóa học thoải mái mà không ảnh hưởng đến các bảng chính. Nhờ JOIN, việc tìm kiếm dữ liệu rất dễ, ví dụ ai đăng ký khóa nào. Khóa ngoại cũng tự động đảm bảo không có lỗi — ví dụ không thể đăng ký sinh viên vào một khóa học không tồn tại.

Lỗi thường gặp với quan hệ "nhiều-nhiều"

Thiếu ràng buộc duy nhất: Nếu không đặt PRIMARY KEY, có thể vô tình thêm trùng một liên kết nhiều lần.

Vi phạm toàn vẹn dữ liệu: Thử chèn bản ghi với student_id hoặc course_id không tồn tại sẽ bị lỗi.

Xóa dữ liệu không đúng thứ tự: Nếu xóa khóa học khỏi courses trước, các bản ghi trong enrollments sẽ thành "mồ côi". Để tránh điều này, hãy dùng ON DELETE CASCADE trong định nghĩa khóa ngoại.

1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Khóa ngoại
Khóa ngoại
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION