Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> SQL

Foreign Key (Khóa ngoại) trong RDBMS


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
D01ITHà Nội
D02HRTP.HCM

Bảng Employee (Child)

EmpID (PK) EmpName EmpAge DeptID (FK)
E001An28D01
E002Bình32D02
E003Cường25NULL

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)

ActionKhi Parent DELETEKhi Parent UPDATE PKYêu cầu
RESTRICT / NO ACTIONChặn xóa (lỗi)Chặn sửa (lỗi)Mặc định. Bảo vệ data con.
CASCADEXóa luôn các row conCập nhật FK của con theoWeak entity, composite PK child.
SET NULLSet FK = NULLSet FK = NULLFK phải cho phép NULL.
SET DEFAULTSet FK = DEFAULT valueSet FK = DEFAULT valueCầ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

  1. Đặt tên constraint rõ ràng: FK_childtable_parenttable hoặc FK_childtable_col.
  2. Luôn index FK.
  3. Chọn ON DELETE/UPDATE action phù hợp nghiệp vụ (CASCADE cho weak entity, SET NULL cho optional).
  4. Dùng Surrogate Key (ID) làm PK/FK thay vì Natural Key (Code, Email) để ổn định.
  5. Kiểm tra circular reference (A→B, B→A) - cần deferrable constraint hoặc xử lý trong transaction.