Quản lý Ràng buộc Khóa ngoại trong MySQL

Ràng buộc khóa ngoại (Foreign Key Constraint) trong MySQL thiết lập một mối quan hệ liên kết giữa các bảng, đảm bảo tính toàn vẹn và nhất quán của dữ liệu. Khi một cột hoặc tập hợp các cột trong một bảng (bảng con) tham chiếu đến cột hoặc tập hợp các cột chứa khóa chính trong một bảng khác (bảng cha), đó chính là mối quan hệ khóa ngoại. Mục đích chính là ngăn chặn các hành động làm mất đi mối liên kết này, chẳng hạn như xóa một bản ghi trong bảng cha mà vẫn còn các bản ghi liên quan trong bảng con.

1. Thiết lập Ràng buộc Khóa ngoại

Để minh họa, chúng ta sẽ tạo một môi trường cơ sở dữ liệu đơn giản:

mysql> CREATE DATABASE quan_ly_nhan_su_db;
Query OK, 1 row affected (0.01 sec)

mysql> USE quan_ly_nhan_su_db;
Database changed

mysql> CREATE TABLE nhan_vien (
    -> ma_nv INT PRIMARY KEY,
    -> ten_nv VARCHAR(50) NOT NULL,
    -> tuoi INT
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO nhan_vien (ma_nv, ten_nv, tuoi) VALUES
    -> (101, 'Nguyen Van A', 30),
    -> (102, 'Tran Thi B', 25),
    -> (103, 'Le Van C', 35);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM nhan_vien;
+-------+--------------+-------+
| ma_nv | ten_nv       | tuoi  |
+-------+--------------+-------+
|   101 | Nguyen Van A |    30 |
|   102 | Tran Thi B   |    25 |
|   103 | Le Van C     |    35 |
+-------+--------------+-------+
3 rows in set (0.00 sec)

Cú pháp cơ bản để định nghĩa khóa ngoại khi tạo bảng là:

CREATE TABLE ten_bang_con (
    cot_1 kieu_du_lieu,
    cot_2 kieu_du_lieu,
    ...
    CONSTRAINT ten_rang_buoc_fk FOREIGN KEY (cot_khoa_ngoai_cua_bang_con)
    REFERENCES ten_bang_cha(cot_khoa_chinh_cua_bang_cha)
    ON DELETE hanh_dong
    ON UPDATE hanh_dong
);

Ví dụ, tạo bảng du_an liên kết với bảng nhan_vien:

mysql> CREATE TABLE du_an (
    -> ma_du_an INT PRIMARY KEY,
    -> ten_du_an VARCHAR(100) NOT NULL,
    -> ma_nv INT,
    -> FOREIGN KEY (ma_nv) REFERENCES nhan_vien(ma_nv)
    -> ON DELETE CASCADE
    -> ON UPDATE CASCADE
    -> );
Query OK, 0 rows affected (0.03 sec)

Trong ví dụ trên, ON DELETE CASCADEON UPDATE CASCADE quy định rằng khi một bản ghi trong bảng cha (nhan_vien) bị xóa hoặc cập nhật, các bản ghi liên quan trong bảng con (du_an) cũng sẽ tự động bị xóa hoặc cập nhật tương ứng. Các tùy chọn khác bao gồm SET NULL, RESTRICT, NO ACTION.

Để tạo ràng buộc khóa ngoại thành công, cần lưu ý một số điều kiện quan trọng:

  • Cả bảng cha và cột được tham chiếu phải tồn tại.
  • Cột được tham chiếu trong bảng cha phải là khóa chính hoặc có một ràng buộc UNIQUE. Cột khóa ngoại trong bảng con sẽ tự động được tạo chỉ mục (index) thông thường.
  • Cơ chế lưu trữ của các bảng phải là InnoDB (mặc định trong MySQL hiện đại).
  • Kiểu dữ liệu của cột khóa ngoại trong bảng con và cột tham chiếu trong bảng cha phải tương thích (tốt nhất là giống hệt nhau).

2. Xóa Ràng buộc Khóa ngoại

Khi cần loại bỏ một ràng buộc khóa ngoại, chúng ta sử dụng lệnh ALTER TABLE. Trước tiên, bạn cần biết tên của ràng buộc khóa ngoại. MySQL thường tự động đặt tên cho các ràng buộc nếu bạn không chỉ định rõ. Bạn có thể tìm tên này bằng cách xem cấu trúc bảng:

mysql> SHOW CREATE TABLE du_an\G
*************************** 1. row ***************************
       Table: du_an
Create Table: CREATE TABLE `du_an` (
  `ma_du_an` int(11) NOT NULL,
  `ten_du_an` varchar(100) NOT NULL,
  `ma_nv` int(11) DEFAULT NULL,
  PRIMARY KEY (`ma_du_an`),
  KEY `ma_nv` (`ma_nv`),
  CONSTRAINT `du_an_ibfk_1` FOREIGN KEY (`ma_nv`) REFERENCES `nhan_vien` (`ma_nv`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

Trong ví dụ trên, tên của ràng buộc khóa ngoại là du_an_ibfk_1. Bây giờ chúng ta có thể xóa nó:

mysql> ALTER TABLE du_an DROP FOREIGN KEY du_an_ibfk_1;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE du_an\G
*************************** 1. row ***************************
       Table: du_an
Create Table: CREATE TABLE `du_an` (
  `ma_du_an` int(11) NOT NULL,
  `ten_du_an` varchar(100) NOT NULL,
  `ma_nv` int(11) DEFAULT NULL,
  PRIMARY KEY (`ma_du_an`),
  KEY `ma_nv` (`ma_nv`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

Lưu ý rằng chỉ mục tự động tạo cho cột khóa ngoại (KEY `ma_nv`) vẫn còn sau khi xóa ràng buộc. Nếu muốn, bạn cũng có thể xóa chỉ mục này.

3. Thêm Ràng buộc Khóa ngoại Hiện có

Nếu bạn muốn thêm một ràng buộc khóa ngoại vào một bảng đã tồn tại, cú pháp tương tự như khi tạo bảng, nhưng sử dụng lệnh ALTER TABLE ADD FOREIGN KEY:

ALTER TABLE ten_bang_con
ADD CONSTRAINT ten_rang_buoc_fk FOREIGN KEY (cot_khoa_ngoai_cua_bang_con)
REFERENCES ten_bang_cha(cot_khoa_chinh_cua_bang_cha)
ON DELETE hanh_dong
ON UPDATE hanh_dong;

Thực hiện thêm lại ràng buộc vào bảng du_an:

mysql> ALTER TABLE du_an
    -> ADD CONSTRAINT fk_du_an_nhan_vien
    -> FOREIGN KEY (ma_nv) REFERENCES nhan_vien(ma_nv)
    -> ON DELETE CASCADE
    -> ON UPDATE CASCADE;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE du_an\G
*************************** 1. row ***************************
       Table: du_an
Create Table: CREATE TABLE `du_an` (
  `ma_du_an` int(11) NOT NULL,
  `ten_du_an` varchar(100) NOT NULL,
  `ma_nv` int(11) DEFAULT NULL,
  PRIMARY KEY (`ma_du_an`),
  KEY `ma_nv` (`ma_nv`),
  CONSTRAINT `fk_du_an_nhan_vien` FOREIGN KEY (`ma_nv`) REFERENCES `nhan_vien` (`ma_nv`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

Ở đây, tôi đã đặt tên rõ ràng cho ràng buộc là fk_du_an_nhan_vien thay vì để MySQL tự tạo, điều này giúp việc quản lý trở nên dễ dàng hơn.

Thẻ: mysql Foreign Key sql Database Design Data Integrity

Đăng vào ngày 10 tháng 6 lúc 02:45