Foreign Key (FK - Khóa ngoại) là cột (hoặc tổ hợp cột) trong một bảng (Child/Referencing table) thiết lập liên kết tham chiếu đến **Primary Key (PK) hoặc Unique Key (UK)** của bảng khác (Parent/Referenced table). Đây là cơ chế cốt lõi thực thi **Referential Integrity (Toàn vẹn tham chiếu)**.
Đặc điểm cơ bản
- FK **không nhất thiết** duy nhất (thường không unique - One-to-Many).
- FK **có thể NULL** (nếu quan hệ optional - ví dụ: nhân viên chưa có phòng ban).
- Giá trị FK **phải tồn tại** trong PK/UK của bảng cha (hoặc NULL).
- PK và FK **phải cùng kiểu dữ liệu** (hoặc tương thích ngầm định).
- Một bảng có thể có **nhiều FK** tham chiếu đến nhiều bảng cha khác nhau.
- Một bảng cha có thể được **nhiều bảng con** tham chiếu.
Ví dụ kinh điển: Employee - Department
Bảng Department (Parent)
| DeptID (PK) | DeptName | DeptZone |
|---|---|---|
| D01 | IT | Hà Nội |
| D02 | HR | TP.HCM |
Bảng Employee (Child)
| EmpID (PK) | EmpName | EmpAge | DeptID (FK) |
|---|---|---|---|
| E001 | An | 28 | D01 |
| E002 | Bình | 32 | D02 |
| E003 | Cường | 25 | NULL |
Mối quan hệ: Employee.DeptID (FK) → Department.DeptID (PK).
Cú pháp SQL tạo Foreign Key
Cách 1: Column-level (trong định nghĩa cột)
CREATE TABLE Employee (
EmpID CHAR(4) PRIMARY KEY,
EmpName VARCHAR(50) NOT NULL,
DeptID CHAR(3),
FOREIGN KEY (DeptID) REFERENCES Department(DeptID)
ON DELETE SET NULL
ON UPDATE CASCADE
);
Cách 2: Table-level (tách riêng - cho composite FK)
CREATE TABLE OrderDetail ( OrderID INT NOT NULL, ProductID INT NOT NULL, Quantity INT, PRIMARY KEY (OrderID, ProductID), FOREIGN KEY (OrderID) REFERENCES Orders(OrderID), FOREIGN KEY (ProductID) REFERENCES Products(ProductID) );
Cách 3: ALTER TABLE thêm FK sau
ALTER TABLE Employee ADD CONSTRAINT FK_Employee_Department FOREIGN KEY (DeptID) REFERENCES Department(DeptID) ON DELETE SET NULL ON UPDATE CASCADE;
Referential Actions (Hành động tham chiếu)
| Action | Khi Parent DELETE | Khi Parent UPDATE PK | Yêu cầu |
|---|---|---|---|
RESTRICT / NO ACTION | Chặn xóa (lỗi) | Chặn sửa (lỗi) | Mặc định. Bảo vệ data con. |
CASCADE | Xóa luôn các row con | Cập nhật FK của con theo | Weak entity, composite PK child. |
SET NULL | Set FK = NULL | Set FK = NULL | FK phải cho phép NULL. |
SET DEFAULT | Set FK = DEFAULT value | Set FK = DEFAULT value | Cần DEFAULT hợp lệ. |
Self-Referencing Foreign Key (FK tự tham chiếu - Unary Relationship)
CREATE TABLE Employee (
EmpID INT PRIMARY KEY,
EmpName VARCHAR(100),
ManagerID INT,
FOREIGN KEY (ManagerID) REFERENCES Employee(EmpID)
ON DELETE SET NULL
);
→ Mối quan hệ Employee (Manager) 1:N Employee (Subordinate).
Foreign Key tham chiếu Unique Key (Không phải PK)
Hợp lệ theo SQL Standard. Ví dụ: Bảng Users có PK UserID và UK Email. Bảng LoginHistory có FK tham chiếu Users.Email.
CREATE TABLE Users (
UserID BIGINT PRIMARY KEY,
Email VARCHAR(255) UNIQUE NOT NULL
);
CREATE TABLE LoginHistory (
LogID BIGINT PRIMARY KEY,
UserEmail VARCHAR(255),
LoginTime TIMESTAMP,
FOREIGN KEY (UserEmail) REFERENCES Users(Email)
ON DELETE CASCADE
);
Lưu ý: Tham chiếu UK ít phổ biến hơn PK. PK ổn định hơn (UK có thể đổi).
Index trên Foreign Key - Bắt buộc cho hiệu suất
- FK **không tự tạo index** trong hầu hết DBMS (trừ một số như SQL Server khi tạo FK qua GUI).
- Luôn tạo index thủ công trên cột FK:
CREATE INDEX idx_emp_dept ON Employee(DeptID); - Lý do: JOIN, FK validation (check parent exists khi insert/update child), ON DELETE CASCADE/SET NULL cần tìm nhanh row con.
Lỗi thường gặp
- Insert child với FK không tồn tại trong parent ->
Foreign Key Constraint Violation. - Delete parent đang có child với
ON DELETE RESTRICT-> lỗi. - Update PK của parent đang bị child tham chiếu với
ON UPDATE RESTRICT-> lỗi. - Kiểu dữ liệu không khớp (VARCHAR(50) vs VARCHAR(100), INT vs BIGINT) -> không tạo được FK.
- Quên index FK -> Deadlock, Full Table Scan khi delete parent, join chậm.
Best Practices
- Đặt tên constraint rõ ràng:
FK_childtable_parenttablehoặcFK_childtable_col. - Luôn index FK.
- Chọn
ON DELETE/UPDATEaction phù hợp nghiệp vụ (CASCADE cho weak entity, SET NULL cho optional). - Dùng Surrogate Key (ID) làm PK/FK thay vì Natural Key (Code, Email) để ổn định.
- Kiểm tra circular reference (A→B, B→A) - cần deferrable constraint hoặc xử lý trong transaction.