Hãy tưởng tượng bạn có hai bảng: một bảng chứa dữ liệu về sinh viên và một bảng khác chứa dữ liệu về các khóa học. Bạn nghĩ làm sao để thể hiện thông tin sinh viên nào đăng ký khóa học nào? Có thể thêm một cột trong bảng sinh viên để lưu tất cả các khóa học mà họ đăng ký, nhưng làm vậy sẽ rất lộn xộn. Một trong những giải pháp ngon nhất là dùng khóa ngoại!
Khóa ngoại (FOREIGN KEY) là một cột hoặc tập hợp các cột dùng để tạo liên kết giữa các bảng. Nó trỏ tới một cột (thường là PRIMARY KEY) ở bảng khác, đảm bảo tính toàn vẹn tham chiếu giữa các bảng. Vậy nên, nếu một sinh viên đăng ký một khóa học, ta chắc chắn rằng khóa học đó thực sự tồn tại.
Khóa ngoại:
- Giúp giữ cho dữ liệu luôn nhất quán, đảm bảo các bản ghi ở một bảng phải khớp với dữ liệu ở bảng khác.
- Làm cho database dễ hiểu và có tổ chức logic.
- Giúp xử lý dữ liệu dễ dàng hơn, tránh trùng lặp và lỗi.
Ví dụ thực tế
Hãy tưởng tượng một thư viện. Bảng books chứa danh sách sách, còn bảng members là danh sách độc giả. Để theo dõi ai mượn sách nào, ta có thể tạo bảng borrowed_books, bảng này sẽ tham chiếu tới books và members qua khóa ngoại. Như vậy, mỗi lần ai đó mượn sách, ta biết chính xác ai mượn và mượn cuốn nào.
Các loại liên kết giữa các bảng
Khóa ngoại cho phép mô tả nhiều kiểu liên kết giữa các bảng. Cùng xem ba loại chính nhé:
1. Liên kết "Một-Một" (ONE-TO-ONE)
Đây là kiểu liên kết đơn giản nhất, một bản ghi ở bảng này chỉ tương ứng với một bản ghi ở bảng kia. Ví dụ, bảng users chứa thông tin người dùng, còn bảng profiles chứa thông tin bổ sung như địa chỉ hoặc ảnh đại diện.
Ví dụ SQL cho liên kết ONE-TO-ONE:
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
username TEXT NOT NULL
);
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY,
user_id INT UNIQUE REFERENCES users(user_id), -- tham chiếu tới users.user_id
address TEXT
);
Ở đây cột user_id trong bảng profiles đóng vai trò là khóa ngoại, tham chiếu tới user_id trong bảng users.
Ví dụ bảng users:
| user_id - PRIMARY KEY | username |
|---|---|
| 1 | alice |
| 2 | bob |
| 3 | charlie |
Ví dụ bảng profiles:
| profile_id - PRIMARY KEY | user_id - FOREIGN KEY | address |
|---|---|---|
| 1 | 1 | Berlin, Germany |
| 2 | 2 | Paris, France |
| 3 | 3 | Tokyo, Japan |
2. Liên kết "Một-Nhiều" (ONE-TO-MANY)
Đây là kiểu liên kết phổ biến nhất. Ví dụ, một khách hàng có thể có nhiều đơn hàng. Trong trường hợp này, bảng customers sẽ liên kết với bảng orders bằng khóa ngoại.
Ví dụ SQL cho liên kết ONE-TO-MANY:
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id), -- tham chiếu tới customers.customer_id
order_date DATE NOT NULL
);
Bảng orders có thể chứa nhiều bản ghi trỏ tới một bản ghi trong bảng customers
Ví dụ bảng customers:
| customer_id - PRIMARY KEY | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
Ví dụ bảng orders:
| order_id - PRIMARY KEY | customer_id - FOREIGN KEY | order_date |
|---|---|---|
| 1 | 1 | 2024-12-01 |
| 2 | 1 | 2024-12-05 |
| 3 | 2 | 2024-12-03 |
| 4 | 3 | 2024-12-07 |
3. Liên kết "Nhiều-Nhiều" (MANY-TO-MANY)
Đôi khi một bản ghi ở bảng này có thể liên kết với nhiều bản ghi ở bảng kia, và ngược lại. Ví dụ, sinh viên đăng ký các khóa học, và một khóa học có thể có nhiều sinh viên. Thường sẽ tạo một bảng trung gian cho trường hợp này.
Ví dụ SQL cho liên kết MANY-TO-MANY:
-- sinh viên
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- khóa học
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL
);
-- "đăng ký sinh viên cụ thể vào khóa học cụ thể"
CREATE TABLE enrollments (
student_id INT REFERENCES students(student_id), -- tham chiếu tới id-sinh viên
course_id INT REFERENCES courses(course_id), -- tham chiếu tới id-khóa học
PRIMARY KEY (student_id, course_id)
);
Ở đây bảng enrollments đóng vai trò "cầu nối" giữa bảng students và courses.
Ví dụ bảng students:
| student_id - PRIMARY KEY | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
Ví dụ bảng courses:
| course_id - PRIMARY KEY | title |
|---|---|
| 1 | SQL Basics |
| 2 | Data Structures |
| 3 | Algorithms |
Ví dụ bảng enrollments:
| student_id - FOREIGN KEY | course_id - FOREIGN KEY |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 3 |
Lợi ích khi dùng khóa ngoại
- Dữ liệu luôn nhất quán. Nếu khóa ngoại trỏ tới bản ghi không tồn tại, PostgreSQL sẽ không cho phép insert hay update dữ liệu.
- Làm việc với bảng dễ hơn. Khóa ngoại giúp liên kết dữ liệu giữa các bảng và thực hiện các truy vấn phức tạp như
JOINdễ dàng. - Tự động hóa hành vi. Bạn có thể cấu hình hành động khi xóa hoặc cập nhật bản ghi liên quan (ví dụ xóa cascade, set
NULLv.v.).
Khóa ngoại trong PostgreSQL trông như thế nào?
Cú pháp tạo khóa ngoại khi tạo bảng:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) -- khóa ngoại-tham chiếu
);
Ở đây:
customer_id— là khóa ngoại.- Nó tham chiếu tới
customer_idtrong bảngcustomers.
Bạn cũng có thể chỉ rõ khóa ngoại bằng FOREIGN KEY:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
Fun fact
Chính thuật ngữ "khóa ngoại" (FOREIGN KEY) xuất phát từ lý thuyết cơ sở dữ liệu quan hệ do Edgar Codd phát triển vào những năm 1970. Thật bất ngờ, ý tưởng này mạnh đến mức đến giờ vẫn là thành phần cốt lõi của database hiện đại. Ai bảo cổ điển là lỗi thời nhỉ?
Giờ thì bạn đã hiểu khóa ngoại là gì và tại sao nó quan trọng. Bạn sẽ còn học cách tạo khóa ngoại khi tạo bảng và cách dùng các thao tác cascade cho chuẩn. Nhưng đó là chuyện của các bài sau nhé!
GO TO FULL VERSION