想象一下你有两张表:一张存学生信息,一张存课程信息。你觉得怎么表达哪些学生选了哪些课程?你可以在学生表里加一列存所有他们选的课程,但这样很快就乱套了。最好的办法之一就是用外键!
外键 (FOREIGN KEY) 就是一列或者几列,用来在表之间建立关联。它指向另一张表的某一列(通常是PRIMARY KEY),保证两张表之间的数据引用是靠谱的。这样,如果某个学生选了某门课,我们就能确定这门课真的存在。
外键的作用:
- 帮你保持数据一致性,保证一张表里的记录在另一张表里也有对应的数据。
- 让数据库结构更清晰、更有逻辑。
- 简化数据处理,防止重复和出错。
现实生活的例子
想象一下图书馆。books表存书的信息,members表存读者的信息。为了追踪谁借了哪本书,我们可以建一个borrowed_books表,通过外键关联books和members。这样每次有人借书,我们都能知道是谁借的,借的是哪本。
表之间的关联类型
外键可以描述不同的表关联。我们来看看三种最常见的类型:
1. 一对一关联 (ONE-TO-ONE)
这是最简单的关联,一张表的一条记录只对应另一张表的一条记录。比如users表存用户信息,profiles表存额外信息,比如地址或照片。
一对一关联的SQL例子:
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), -- 指向 users.user_id
address TEXT
);
这里profiles表里的user_id列就是外键,指向users表的user_id。
users表的例子:
| user_id - PRIMARY KEY | username |
|---|---|
| 1 | alice |
| 2 | bob |
| 3 | charlie |
profiles表的例子:
| profile_id - PRIMARY KEY | user_id - FOREIGN KEY | address |
|---|---|---|
| 1 | 1 | Berlin, Germany |
| 2 | 2 | Paris, France |
| 3 | 3 | Tokyo, Japan |
2. 一对多关联 (ONE-TO-MANY)
这是最常见的关联。比如一个客户可以有很多订单。这时customers表和orders表通过外键关联。
一对多关联的SQL例子:
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), -- 指向 customers.customer_id
order_date DATE NOT NULL
);
orders表可以有多条记录指向customers表的一条记录。
customers表的例子:
| customer_id - PRIMARY KEY | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
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. 多对多关联 (MANY-TO-MANY)
有时候一张表的一条记录可以和另一张表的多条记录关联,反过来也一样。比如学生选课,一个学生可以选多门课,一门课也可以有很多学生。通常我们会建一张中间表。
多对多关联的SQL例子:
-- 学生
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- 课程
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL
);
-- "某个学生选了某门课"
CREATE TABLE enrollments (
student_id INT REFERENCES students(student_id), -- 指向学生id
course_id INT REFERENCES courses(course_id), -- 指向课程id
PRIMARY KEY (student_id, course_id)
);
这里enrollments表就是students和courses之间的“桥”。
students表的例子:
| student_id - PRIMARY KEY | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
courses表的例子:
| course_id - PRIMARY KEY | title |
|---|---|
| 1 | SQL Basics |
| 2 | Data Structures |
| 3 | Algorithms |
enrollments表的例子:
| student_id - FOREIGN KEY | course_id - FOREIGN KEY |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 3 |
用外键的好处
- 数据保持一致。 如果外键指向不存在的记录,PostgreSQL不会让你插入或更新数据。
- 表操作更简单。 外键让你轻松把表的数据关联起来,还能写各种复杂的
JOIN查询。 - 自动行为。 你可以设置删除或更新关联记录时的动作(比如级联删除、设为
NULL等)。
PostgreSQL里的外键长啥样?
创建表时加外键的语法:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) -- 外键引用
);
这里:
customer_id—— 这是外键。- 它指向
customers表的customer_id。
你也可以用FOREIGN KEY显式声明外键:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
有趣的事实
“外键”(FOREIGN KEY)这个词来自1970年代Edgar Codd搞出来的关系型数据库理论。神奇的是,这个核心思想到现在还是现代数据库的关键。谁说经典不过时?
现在你已经明白外键是啥、为啥它很重要了。你还会学到怎么在建表时加外键,怎么用好级联操作——这些我们下节课再聊!
GO TO FULL VERSION