一、先明确:为什么必须掌握多表查询?
1.你是否能区分不同多表查询方式的差异?
2.能否根据业务场景选择合适的查询方式?
3.能否独立写出正确的多表查询 sql?(避免语法错误)
二、先铺垫:多表查询的基础前提
先明确多表查询的核心:表与表之间必须有 “关联关系”(通常是主键 - 外键关联,比如用户表user的id(主键)对应订单表order的user_id(外键)),没有关联关系的多表查询会产生 “笛卡尔积”(数据冗余,无实际业务意义)。
先定义两个测试表:
-- 用户表(主表) create table `user` ( `id` int primary key auto_increment, -- 用户id(主键) `username` varchar(50) not null, -- 用户名 `age` int default 0 -- 年龄 ); -- 订单表(从表) create table `order` ( `id` int primary key auto_increment, -- 订单id(主键) `order_no` varchar(30) not null, -- 订单编号 `user_id` int not null, -- 关联用户表的用户id(外键) `price` decimal(10,2) not null, -- 订单金额 foreign key (`user_id`) references `user`(`id`) -- 外键约束 );
三、核心多表查询方式拆解
方式 1:join 连接查询
join是多表查询的核心方式,通过关联字段将多个表 “拼接” 在一起查询,核心分为内连接、外连接(左外连接、右外连接)、交叉连接(极少用,仅作了解)。
1.1 内连接(inner join / join)
通俗定义:只查询 “两张表中满足关联条件” 的数据,不满足条件的记录会被过滤掉(相当于 “取两张表的交集”)。
语法:select 字段 from 表1 inner join 表2 on 表1.关联字段 = 表2.关联字段 [where 条件](inner可省略,直接写join)。
-- 简洁写法(省略inner) select u.id as user_id, u.username, o.id as order_id, o.order_no, o.price from `user` u join `order` o on u.id = o.user_id; -- 关联条件:用户id=订单的用户id
考察点:你是否知道on用于指定表关联条件,where用于过滤查询结果(避免把关联条件写在where中)。
1.2 左外连接(left join / left outer join)
通俗定义:以 “左表” 为基准,查询左表的所有数据,右表中满足关联条件的数据会被匹配显示,不满足条件的右表字段显示null(相当于 “左表全量数据 + 右表交集数据”)。
语法:select 字段 from 左表 left join 右表 on 关联条件 [where 条件](outer可省略)。
select u.id as user_id, u.username, o.id as order_id, o.order_no, o.price from `user` u left join `order` o on u.id = o.user_id;
考察点:能否区分左表和右表,理解 “右表不满足条件显示 null” 的特性。
1.3 右外连接(right join / right outer join)
通俗定义:以 “右表” 为基准,查询右表的所有数据,左表中满足关联条件的数据会被匹配显示,不满足条件的左表字段显示null(相当于 “右表全量数据 + 左表交集数据”),功能上可通过左连接互换表位置实现。
语法:select 字段 from 左表 right join 右表 on 关联条件 [where 条件](outer可省略)。
select u.id as user_id, u.username, o.id as order_id, o.order_no, o.price from `user` u right join `order` o on u.id = o.user_id;
考察点:知道右连接的存在,理解其与左连接的对称关系。
1.4 交叉连接(cross join,极少用)
通俗定义:无关联条件的连接,会产生两张表的 “笛卡尔积”(数据行数 = 表 1 行数 × 表 2 行数),通常无实际业务意义,仅在特殊场景(比如生成测试数据)使用。
sql 示例:
-- 产生笛卡尔积,慎用 select u.username, o.order_no from `user` u cross join `order` o;
方式 2:子查询(嵌套查询,适合简单场景)
通俗定义:将一个查询语句(子查询 / 内层查询)嵌套在另一个查询语句(主查询 / 外层查询)中,子查询的结果作为主查询的条件或数据源,分为 “关联子查询” 和 “非关联子查询”。
非关联子查询:子查询可独立执行,结果不依赖主查询(适合简单条件过滤)
- 示例:查询 “购买过订单金额大于 100 元的用户” 信息
select id, username, age
from `user`
where id in ( -- 子查询:获取订单金额>100的所有用户id
select distinct user_id from `order` where price > 100
);关联子查询:子查询依赖主查询的字段,无法独立执行(适合 “按主表每条记录匹配子表” 的场景)
- 示例:查询 “每个用户的最新订单”(按订单 id 倒序取第一条)
select u.id as user_id, u.username, o.id as order_id, o.order_no, o.price
from `user` u
join `order` o on u.id = o.user_id
where o.id = ( -- 子查询:关联主表的user_id,取该用户最大订单id(最新订单)
select max(id) from `order` where user_id = u.id
);考察点:能否区分关联 / 非关联子查询,知道子查询的适用边界(避免多层嵌套导致性能问题)。
方式 3:联合查询(union / union all,结果集合并)
通俗定义:将多个select查询的结果集合并成一个结果集,要求所有查询的 “字段数量、字段类型、字段顺序” 一致,分为union(去重,会过滤重复记录)和union all(不去重,性能更高)。
语法:select 字段 from 表1 [where 条件] union [all] select 字段 from 表2 [where 条件];
-- union:去重(自动过滤重复的用户记录) select id, username, age from `user` where age > 25 union select u.id, u.username, u.age from `user` u join `order` o on u.id = o.user_id where o.price > 200; -- union all:不去重(性能更高,适合确定无重复数据的场景) select id, username, age from `user` where age > 25 union all select u.id, u.username, u.age from `user` u join `order` o on u.id = o.user_id where o.price > 200;
考察点:知道union和union all的区别,明确联合查询的字段要求。
| 查询方式 | 核心特点 | 适用场景 | 性能优先级 |
|---|---|---|---|
| inner join | 取两表交集,过滤无效数据 | 关联数据必须存在的业务(如已下单用户) | 高(优先使用) |
| left join | 保留左表全量数据,右表补 null | 需显示主表所有数据的场景(如所有用户订单) | 高 |
| 子查询 | 嵌套查询,逻辑直观 | 简单条件过滤(如根据子查询结果筛选主表) | 中(复杂场景不如 join) |
| union / union all | 合并结果集 | 多查询结果合并(如不同条件的同类数据) | 中(union all > union) |
加分项
1、结合项目举例:“我在实训项目中,用left join查询所有用户及对应的订单列表,用inner join查询有支付记录的用户信息”;
2、性能意识:“复杂多表查询优先用join,不用多层子查询;合并结果集时,确定无重复数据就用union all,比union快”;
3、细节把控:“join的关联条件写在on里,过滤条件写在where里,避免笛卡尔积冗余”。
举一反三
1、“如何查询‘没有订单记录的用户’?”(答案:left join后判断订单字段为null,select u.* from user u left join order o on u.id=o.user_id where o.id is null);
2. “on和where在join查询中有什么区别?”(答案:on是表关联条件,先执行;where是结果过滤条件,在表关联后执行;left join中,on不过滤左表数据,where会过滤);
3. “多表查询时,如何提高性能?”(答案:给关联字段(主键 / 外键)建索引;避免select *,只查需要的字段;减少笛卡尔积产生)。
以上就是mysql中多表查询的方式总结的详细内容,更多关于mysql多表查询方式的资料请关注代码网其它相关文章!
发表评论