Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL连表查询

一文带你掌握MySQL中的连表查询

作者:盛夏绽放

在 MySQL 中,连表查询是通过关联多个表的共同字段整合数据的核心操作,本文将基于真实的业务表(用户表、订单表、商品表),详细讲解所有连表查询类型的语法、作用、执行结果,并对比彼此的核心差异,让你直观理解各类连表查询的特点

一、准备工作:创建真实业务表并插入测试数据

我们以电商场景的用户表(user)、订单表(order)、 商品表(product) 为例,先创建表并插入测试数据(注意:order是 MySQL 关键字,需用反引号``包裹)。

1. 创建表结构

-- 1. 用户表(存储用户基本信息)
CREATE TABLE `user` (
    user_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID(主键)',
    user_name VARCHAR(50) NOT NULL COMMENT '用户名',
    user_phone VARCHAR(20) COMMENT '用户手机号',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 2. 商品表(存储商品信息)
CREATE TABLE `product` (
    product_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '商品ID(主键)',
    product_name VARCHAR(100) NOT NULL COMMENT '商品名称',
    price DECIMAL(10,2) NOT NULL COMMENT '商品价格',
    stock INT DEFAULT 0 COMMENT '商品库存'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 3. 订单表(存储用户订单,关联用户表和商品表)
CREATE TABLE `order` (
    order_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '订单ID(主键)',
    user_id INT NOT NULL COMMENT '用户ID(关联user表的user_id)',
    product_id INT NOT NULL COMMENT '商品ID(关联product表的product_id)',
    order_amount DECIMAL(10,2) NOT NULL COMMENT '订单金额',
    order_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '下单时间',
    -- 外键约束(可选,用于强制数据完整性)
    FOREIGN KEY (user_id) REFERENCES `user`(user_id),
    FOREIGN KEY (product_id) REFERENCES `product`(product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2. 插入测试数据

-- 插入用户数据(3个用户:张三、李四、王五,其中王五暂无订单)
INSERT INTO `user` (user_name, user_phone) VALUES
('张三', '13800138000'),
('李四', '13900139000'),
('王五', '13700137000');

-- 插入商品数据(3个商品:手机、电脑、耳机)
INSERT INTO `product` (product_name, price, stock) VALUES
('华为Mate60', 6999.00, 100),
('苹果MacBook Pro', 12999.00, 50),
('索尼WH-1000XM5', 2499.00, 200);

-- 插入订单数据(4个订单:张三买了手机和耳机,李四买了电脑,无王五的订单,且有一个订单关联的商品ID为4(不存在的商品))
INSERT INTO `order` (user_id, product_id, order_amount) VALUES
(1, 1, 6999.00),  -- 张三买华为Mate60
(1, 3, 2499.00),  -- 张三买索尼耳机
(2, 2, 12999.00), -- 李四买苹果电脑
(2, 4, 0.00);     -- 李四买了一个不存在的商品(product_id=4)

3. 表数据预览

表名数据内容
useruser_id:1(张三)、2(李四)、3(王五)
productproduct_id:1(华为 Mate60)、2(苹果 MacBook Pro)、3(索尼耳机)
orderorder_id:1(1-1-6999)、2(1-3-2499)、3(2-2-12999)、4(2-4-0)

二、各类连表查询详解(附语法、结果、作用)

1. 交叉连接(CROSS JOIN):笛卡尔积连接

作用

返回两个表的笛卡尔积(表 A 的每一行与表 B 的每一行组合),无任何条件匹配,实际业务中极少直接使用,通常需配合WHERE过滤。

语法

-- 显式交叉连接(用户表 × 商品表)
SELECT u.user_name, p.product_name 
FROM `user` u
CROSS JOIN `product` p;

执行结果(共 3×3=9 行)

user_nameproduct_name
张三华为 Mate60
张三苹果 MacBook Pro
张三索尼 WH-1000XM5
李四华为 Mate60
李四苹果 MacBook Pro
李四索尼 WH-1000XM5
王五华为 Mate60
王五苹果 MacBook Pro
王五索尼 WH-1000XM5

特点

2. 内连接(INNER JOIN):匹配连接(最常用)

作用

只返回两个 / 多个表中满足关联条件的行(即交集),是业务中使用频率最高的连表查询。

语法(查询用户的订单及对应商品信息)

-- 显式内连接(推荐,可读性高)
SELECT 
    u.user_name,
    o.order_id,
    p.product_name,
    o.order_amount
FROM `user` u
INNER JOIN `order` o ON u.user_id = o.user_id
INNER JOIN `product` p ON o.product_id = p.product_id;

-- 隐式内连接(省略INNER JOIN,用WHERE指定条件,功能一致)
SELECT 
    u.user_name,
    o.order_id,
    p.product_name,
    o.order_amount
FROM `user` u, `order` o, `product` p
WHERE u.user_id = o.user_id AND o.product_id = p.product_id;

执行结果(仅保留匹配的行,共 3 行)

user_nameorder_idproduct_nameorder_amount
张三1华为 Mate606999.00
张三2索尼 WH-1000XM52499.00
李四3苹果 MacBook Pro12999.00

关键说明

3. 外连接(OUTER JOIN):保留单侧 / 双侧未匹配行

外连接分为左外连接、右外连接、全外连接(MySQL 不直接支持全外连接,需用 UNION 实现),核心是保留一侧 / 双侧表的所有行,无匹配时显示NULL

(1)左外连接(LEFT JOIN / LEFT OUTER JOIN)

作用:保留左表(JOIN左侧的表)的所有行,右表仅匹配满足条件的行;若右表无匹配,右表字段显示NULL

语法(查询所有用户的订单,包括无订单的用户)

-- 左外连接:保留用户表的所有行
SELECT 
    u.user_name,
    o.order_id,
    p.product_name,
    o.order_amount
FROM `user` u
LEFT JOIN `order` o ON u.user_id = o.user_id
LEFT JOIN `product` p ON o.product_id = p.product_id;

执行结果(共 5 行,包含王五和李四的无效订单)

user_nameorder_idproduct_nameorder_amount
张三1华为 Mate606999.00
张三2索尼 WH-1000XM52499.00
李四3苹果 MacBook Pro12999.00
李四4NULL0.00
王五NULLNULLNULL

关键说明

在这段左外连接 SQL 中,第一个LEFT JOIN的左表是FROM后的user表(别名u),而后续的LEFT JOIN的左表是前一个连接的结果集(即userorder连接后的临时表)。

分步拆解说明

我们把 SQL 拆成两步,你会更清晰:

第一步:user LEFT JOIN order

-- 左表:user(u),右表:order(o)
SELECT u.user_name, o.order_id
FROM `user` u
LEFT JOIN `order` o ON u.user_id = o.user_id;

第二步:再 LEFT JOIN product

-- 左表:第一步得到的临时表(user+order),右表:product(p)
SELECT ...
FROM (user u LEFT JOIN order o ON ...)  -- 这是新的左表
LEFT JOIN `product` p ON o.product_id = p.product_id;

核心规律(通用)

在 MySQL 的多表连接中:

比如你的 SQL 中,即使后续连接product,也不会丢失user表的行(比如王五无订单的行、李四的无效订单行都会保留)。

(2)右外连接(RIGHT JOIN / RIGHT OUTER JOIN)

作用:保留右表(JOIN右侧的表)的所有行,左表仅匹配满足条件的行;若左表无匹配,左表字段显示NULL

语法(查询所有商品的订单,包括无订单的商品)

-- 右外连接:保留商品表的所有行
SELECT 
    u.user_name,
    o.order_id,
    p.product_name,
    o.order_amount
FROM `user` u
INNER JOIN `order` o ON u.user_id = o.user_id
RIGHT JOIN `product` p ON o.product_id = p.product_id;

执行结果(共 3 行,无订单的商品显示 NULL)

user_nameorder_idproduct_nameorder_amount
张三1华为 Mate606999.00
李四3苹果 MacBook Pro12999.00
张三2索尼 WH-1000XM52499.00

扩展:若要保留商品表全量(包括无订单的商品,需调整连接顺序)

SELECT 
    u.user_name,
    o.order_id,
    p.product_name,
    o.order_amount
FROM `product` p
RIGHT JOIN `order` o ON p.product_id = o.product_id
LEFT JOIN `user` u ON o.user_id = u.user_id;
-- 结果会包含product_id=4的无效订单,以及所有商品(若有商品无订单则显示NULL)

(3)全外连接(FULL JOIN / FULL OUTER JOIN)

作用:保留左表和右表的所有行,无匹配的一侧字段显示NULL(即左外连接 + 右外连接的并集)。

注意:MySQL 不直接支持 FULL JOIN,需通过LEFT JOIN UNION RIGHT JOIN实现

语法(查询所有用户和所有商品的订单,无匹配则显示 NULL)

-- 左外连接部分:所有用户 + 匹配的订单/商品
SELECT 
    u.user_name,
    o.order_id,
    p.product_name,
    o.order_amount
FROM `user` u
LEFT JOIN `order` o ON u.user_id = o.user_id
LEFT JOIN `product` p ON o.product_id = p.product_id

UNION  -- UNION去重,UNION ALL保留重复行

-- 右外连接部分:所有商品 + 匹配的订单/用户
SELECT 
    u.user_name,
    o.order_id,
    p.product_name,
    o.order_amount
FROM `user` u
RIGHT JOIN `order` o ON u.user_id = o.user_id
RIGHT JOIN `product` p ON o.product_id = p.product_id;

执行结果(包含所有用户、所有商品、所有订单,无匹配则 NULL)

user_nameorder_idproduct_nameorder_amount
张三1华为 Mate606999.00
张三2索尼 WH-1000XM52499.00
李四3苹果 MacBook Pro12999.00
李四4NULL0.00
王五NULLNULLNULL

4. 自然连接(NATURAL JOIN):自动匹配同名字段

作用

自动根据两个表中名称相同的字段进行连接(无需手动写ON条件),分为自然内连接、自然左 / 右外连接。

语法(自动匹配user_id字段,查询用户和订单)

-- 自然内连接(自动匹配user_id字段)
SELECT 
    user_name,
    order_id,
    order_amount
FROM `user` u
NATURAL JOIN `order` o;

执行结果(等同于 INNER JOIN ON u.user_id = o.user_id,共 4 行)

user_nameorder_idorder_amount
张三16999.00
张三22499.00
李四312999.00
李四40.00

特点

5. 自连接(SELF JOIN):表自身连接

作用

将表与自身进行连接(把一个表当作两个表使用),用于查询表内的层级关系或关联数据(如员工与上级、分类与子分类)。

扩展:新增员工表并演示自连接

-- 创建员工表(包含员工ID和上级ID,上级ID关联自身的员工ID)
CREATE TABLE `employee` (
    emp_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工ID',
    emp_name VARCHAR(50) NOT NULL COMMENT '员工姓名',
    manager_id INT COMMENT '上级ID(关联emp_id)',
    department VARCHAR(50) COMMENT '部门'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 插入测试数据
INSERT INTO `employee` (emp_name, manager_id, department) VALUES
('马云', NULL, '董事会'),       -- 马云无上级
('张勇', 1, 'CEO办公室'),      -- 张勇的上级是马云
('王坚', 2, '阿里云'),         -- 王坚的上级是张勇
('蒋芳', 2, '廉政部');         -- 蒋芳的上级是张勇

-- 自连接查询:每个员工的姓名及对应的上级姓名
SELECT 
    e.emp_name AS 员工姓名,
    m.emp_name AS 上级姓名,
    e.department AS 部门
FROM `employee` e
LEFT JOIN `employee` m ON e.manager_id = m.emp_id;

执行结果

员工姓名上级姓名部门
马云NULL董事会
张勇马云CEO 办公室
王坚张勇阿里云
蒋芳张勇廉政部

特点

三、各类连表查询的核心差异对比表

连接类型核心逻辑结果集特点匹配条件指定方式常用场景
交叉连接(CROSS)笛卡尔积,无匹配行数 = 表 A× 表 B,无意义组合多无(或 WHERE 过滤)测试数据、特殊数据生成
内连接(INNER)仅匹配满足条件的行(交集)只保留匹配行,无 NULLON/WHERE业务核心查询(如用户 + 订单)
左外连接(LEFT)保留左表所有行,右表匹配左表全量,右表无匹配则 NULLON查主表全量 + 关联表数据(所有用户 + 订单)
右外连接(RIGHT)保留右表所有行,左表匹配右表全量,左表无匹配则 NULLON查关联表全量 + 主表数据(所有订单 + 用户)
全外连接(FULL)保留左右表所有行(并集)左右表全量,无匹配则 NULLON(MySQL 需 UNION 实现)查两个表的所有数据(极少用)
自然连接(NATURAL)自动匹配同名字段同内 / 外连接,但依赖字段名自动(无需 ON)简单场景(不推荐生产使用)
自连接(SELF)表自身关联同内 / 外连接,处理表内层级ON(表别名区分)层级数据查询(员工 - 上级、分类 - 子分类)

四、关键注意事项

关联键索引:连表查询的关联键(如user.user_idorder.user_id)需建立索引,否则会触发全表扫描,性能极差;

NULL 值处理:外连接的 NULL 字段需用IFNULL()/COALESCE()处理(如IFNULL(o.order_amount, 0.00)),避免业务逻辑异常;

表别名:多表连接时建议使用表别名(如u代表usero代表order),简化 SQL 并提高可读性;

优先级JOIN的执行优先级高于WHERE,因此关联条件写在ON中比WHERE中更高效(尤其是外连接)。

到此这篇关于一文带你掌握MySQL中的连表查询的文章就介绍到这了,更多相关MySQL连表查询内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文