Bài 8: Khóa chính (Primary Key) và Khóa ngoại (Foreign Key) – Sợi dây kết nối dữ liệu


I. Mục đích (Objectives)

Sau bài học này, người đọc sẽ:

  • Hiểu tại sao phải tách dữ liệu thành nhiều bảng thay vì gộp chung một bảng (vấn đề dư thừa dữ liệu).
  • Phân biệt rõ ràng vai trò của Khóa chính (PK) và Khóa ngoại (FK).
  • Biết cách thiết kế mối quan hệ Một – Nhiều (1-n): Ví dụ Một Lớp có nhiều Học sinh.
  • Thực hành tạo ràng buộc khóa ngoại trong SQLite để bảo vệ tính toàn vẹn dữ liệu.

II. Yêu cầu (Prerequisites)

  • Hiểu cách tạo bảng (CREATE TABLE) và kiểu dữ liệu cơ bản.

III. Nội dung chi tiết (Detailed Content)

1. Đặt vấn đề: Tại sao cần chia bảng?

Hãy tưởng tượng bạn lưu danh sách học sinh như sau trong 1 bảng duy nhất:

id ho_ten ten_lop giao_vien_cn
1 Nguyễn Văn A 10A1 Thầy Hùng
2 Trần Thị B 10A1 Thầy Hùng
3 Lê Văn C 10A1 Thầy Hùng

Vấn đề gặp phải (Sự dư thừa):

  • Thông tin “10A1” và “Thầy Hùng” bị lặp lại liên tục.
  • Rủi ro cập nhật: Nếu Thầy Hùng chuyển công tác, bạn phải sửa hàng trăm dòng dữ liệu của học sinh lớp 10A1. Nếu sót 1 dòng -> dữ liệu bị sai lệch (Inconsistent).

Giải pháp: Tách thành 2 bảng riêng biệt:

  1. Bảng LopHoc: Chỉ lưu thông tin lớp.
  2. Bảng HocSinh: Chỉ lưu thông tin học sinh và một “mã code” để trỏ sang bảng lớp.

2. Khóa chính (Primary Key – PK)

  • Định nghĩa: Là cột dùng để định danh duy nhất cho mỗi dòng trong bảng. Giống như số CCCD của mỗi công dân.
  • Đặc điểm: Không được trùng lặp, không được để trống (NULL).
  • Trong SQLite: Thường dùng cột id kiểu INTEGER PRIMARY KEY AUTOINCREMENT.

3. Khóa ngoại (Foreign Key – FK)

  • Định nghĩa: Là một cột trong bảng này dùng để tham chiếu đến Khóa chính của bảng khác. Nó là “sợi dây” nối 2 bảng lại với nhau.
  • Quy tắc: Giá trị của Khóa ngoại phải tồn tại bên bảng Khóa chính (hoặc là NULL). Bạn không thể gán học sinh vào một lớp có mã số là 99 nếu bảng Lớp học chưa có lớp 99.

4. Thực hành: Thiết kế quan hệ 1-n (Một Lớp – Nhiều Học sinh)

Chúng ta sẽ thực hiện lại thiết kế CSDL (Nên xóa các bảng cũ để làm lại cho sạch).
Bước 1: Tạo bảng Cha (Parent Table) – Bảng LopHoc
Phải tạo bảng này trước vì nó bị phụ thuộc.

CREATE TABLE LopHoc (
    id_lop INTEGER PRIMARY KEY AUTOINCREMENT,
    ten_lop TEXT NOT NULL,
    giao_vien_cn TEXT
);

-- Thêm dữ liệu mẫu
INSERT INTO LopHoc (ten_lop, giao_vien_cn) VALUES ('10A1', 'Thầy Hùng');
INSERT INTO LopHoc (ten_lop, giao_vien_cn) VALUES ('10A2', 'Cô Mai');

(Lúc này: Lớp 10A1 có id_lop = 1, Lớp 10A2 có id_lop = 2)
Bước 2: Tạo bảng Con (Child Table) – Bảng HocSinh có chứa FK
Đây là phần quan trọng nhất.

CREATE TABLE HocSinh (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    ho_ten TEXT NOT NULL,
    diem_tb REAL,
    ma_lop_id INTEGER, -- Đây là cột Khóa ngoại
    FOREIGN KEY (ma_lop_id) REFERENCES LopHoc(id_lop)
);

Giải thích code:

  • ma_lop_id INTEGER: Tạo một cột bình thường để chứa mã lớp.
  • FOREIGN KEY (ma_lop_id) REFERENCES LopHoc(id_lop): Khai báo với SQLite rằng cột ma_lop_id này là khóa ngoại, nó tham chiếu tới cột id_lop của bảng LopHoc.

Bước 3: Thêm dữ liệu (Insert)

-- Thêm em An vào lớp 10A1 (id_lop = 1)
INSERT INTO HocSinh (ho_ten, diem_tb, ma_lop_id) VALUES ('Nguyễn Văn An', 8.5, 1);

-- Thêm em Bích vào lớp 10A2 (id_lop = 2)
INSERT INTO HocSinh (ho_ten, diem_tb, ma_lop_id) VALUES ('Trần Thị Bích', 9.0, 2);

5. Lưu ý quan trọng về Ràng buộc toàn vẹn (Integrity Constraint)

Mặc định, để đảm bảo tính tương thích ngược, SQLite TẮT tính năng kiểm tra khóa ngoại. Nghĩa là bạn điền ma_lop_id = 999 (lớp không tồn tại), nó vẫn cho phép.
Để bật tính năng bảo vệ dữ liệu (bắt buộc phải làm trong CNPM), bạn phải chạy lệnh này mỗi khi kết nối database:

PRAGMA foreign_keys = ON;

Sau khi chạy lệnh trên, nếu bạn cố tình thêm một học sinh vào lớp không tồn tại:

INSERT INTO HocSinh (ho_ten, ma_lop_id) VALUES ('Em Hư', 999);

-> Kết quả: SQLite sẽ báo lỗi: FOREIGN KEY constraint failed. -> Dữ liệu được bảo vệ an toàn.

IV. Tổng kết (Summary)

Bài học này đã giúp bạn xây dựng nền móng vững chắc cho hệ thống:

  1. Khóa chính (PK): Định danh bản ghi.
  2. Khóa ngoại (FK): Liên kết các bảng.
  3. Toàn vẹn dữ liệu: Đảm bảo không có dữ liệu “mồ côi” (Học sinh thuộc về một lớp không tồn tại).

Tuy nhiên, dữ liệu bây giờ đang nằm ở 2 bảng riêng biệt. Khi sếp hỏi: “In cho tôi danh sách học sinh kèm tên lớp và tên giáo viên chủ nhiệm”, làm sao để lấy thông tin từ cả 2 bảng cùng lúc?
Đó là nhiệm vụ của Bài 9: Truy vấn nhiều bảng (JOINs). Chúng ta sẽ học cách “hàn” 2 bảng lại với nhau để lấy dữ liệu thống nhất.

You may also like...

Để lại một bình luận