你提到的「链表查询」「外键连接」其实是指 多表关联查询(JOIN 查询) ,
MySQL 中主要有 6 种关联方式。我来给你系统讲解原理、语法、区别,并配完整例子。
🧩 一、准备示例表结构
我们以一个常见的用户-订单系统为例:
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
email VARCHAR(100)
);
-- 订单表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
order_no VARCHAR(20),
amount DECIMAL(10,2),
FOREIGN KEY (user_id) REFERENCES users(id) -- 外键关联 users.id
);
数据示例:
INSERT INTO users (name, email) VALUES
('张三', 'zhang@example.com'),
('李四', 'li@example.com'),
('王五', 'wang@example.com');
INSERT INTO orders (user_id, order_no, amount) VALUES
(1, 'A1001', 200.50),
(1, 'A1002', 150.00),
(2, 'A2001', 99.99);
🚀 二、MySQL 的 6 种 JOIN 查询方式
① INNER JOIN(内连接)
✅ 只返回两个表中匹配到的记录。
SELECT users.name, orders.order_no, orders.amount
FROM users
INNER JOIN orders ON users.id = orders.user_id;
🔍 结果:
| name | order_no | amount |
|---|---|---|
| 张三 | A1001 | 200.50 |
| 张三 | A1002 | 150.00 |
| 李四 | A2001 | 99.99 |
👉 没有订单的用户(王五)不会显示。
② LEFT JOIN(左连接)
✅ 返回左表的全部数据,即使右表没有匹配。
SELECT users.name, orders.order_no, orders.amount
FROM users
LEFT JOIN orders ON users.id = orders.user_id;
🔍 结果:
| name | order_no | amount |
|---|---|---|
| 张三 | A1001 | 200.50 |
| 张三 | A1002 | 150.00 |
| 李四 | A2001 | 99.99 |
| 王五 | NULL | NULL |
👉 王五 没有订单,也会出现。
③ RIGHT JOIN(右连接)
✅ 与 LEFT JOIN 相反,返回右表全部数据。
SELECT users.name, orders.order_no, orders.amount
FROM users
RIGHT JOIN orders ON users.id = orders.user_id;
🔍 结果与 INNER JOIN 类似,因为订单表中的 user_id 都匹配成功。
④ FULL OUTER JOIN(全外连接)
⚠️ MySQL 不直接支持(但可以用
UNION模拟)。
✅ 返回左表 + 右表所有数据,没有匹配的补 NULL。
SELECT users.name, orders.order_no, orders.amount
FROM users
LEFT JOIN orders ON users.id = orders.user_id
UNION
SELECT users.name, orders.order_no, orders.amount
FROM users
RIGHT JOIN orders ON users.id = orders.user_id;
🔍 会包含所有用户和所有订单(哪怕不匹配)。
⑤ CROSS JOIN(交叉连接)
✅ 返回笛卡尔积(两表所有行两两组合)。
SELECT users.name, orders.order_no
FROM users
CROSS JOIN orders;
假设 users 3 行,orders 3 行,
👉 结果 = 3 × 3 = 9 行。
⑥ SELF JOIN(自连接)
✅ 同一张表自己关联自己,用别名区分。
例:查询每个用户的“推荐人”
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
manager_id INT
);
-- 查询员工与上级名字
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
🧠 三、外键 (FOREIGN KEY) 的作用
外键保证数据的一致性。
比如 orders.user_id 必须在 users.id 中存在,否则不能插入。
- ON DELETE CASCADE:删除用户时自动删除其订单。
- ON UPDATE CASCADE:修改用户 id 时,自动更新订单表中对应的 user_id。
示例:
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
order_no VARCHAR(20),
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
🔍 四、复杂多表链式 JOIN 示例
三表:用户、订单、商品:
SELECT u.name AS 用户名,
o.order_no AS 订单号,
p.product_name AS 商品名,
p.price AS 单价
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.id = p.order_id;
这就是「链表查询」的含义:多表逐级关联。
🧩 五、在 NestJS + TypeORM 中实现相同查询
TypeORM 写法:
const result = await this.userRepository
.createQueryBuilder('u')
.leftJoinAndSelect('u.orders', 'o')
.leftJoinAndSelect('o.products', 'p')
.select(['u.name', 'o.order_no', 'p.product_name', 'p.price'])
.getMany();
对应 SQL:
SELECT u.name, o.order_no, p.product_name, p.price
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
LEFT JOIN products p ON o.id = p.order_id;
✅ 总结表格
| JOIN 类型 | 含义 | 结果包含哪些数据 |
|---|---|---|
| INNER JOIN | 内连接 | 两边都匹配的 |
| LEFT JOIN | 左连接 | 左表全部,右表匹配的 |
| RIGHT JOIN | 右连接 | 右表全部,左表匹配的 |
| FULL JOIN | 全连接 | 所有匹配 + 不匹配的 |
| CROSS JOIN | 笛卡尔积 | 所有组合 |
| SELF JOIN | 自连接 | 一张表自己关联 |