️ SQL 核心概念JOIN 和 UNION 到底有什么区别一个比喻彻底搞懂再也不混淆 2024 | ️ SQL技术博客 | ️ MySQL · JOIN · UNION · 数据库 先说结论很多初学者容易把 JOIN 和 UNION 搞混因为它们都是把两张表合在一起。但合并的方向完全不同JOIN是把两张表左右合并像把两张纸并排贴在一起。UNION是把两张表上下合并像把两张纸上下拼接成一张长纸。用一张图来理解JOIN左右合并 UNION上下合并 表A 表B 结果 表A 结果 ───── ───── ─────────── ───── ───── 行1 行X 行1 | 行X 行1 行1 行2 行Y 行2 | 行Y 行2 行2 行3 行Z 行3 | 行Z ───── 行3 表B ───── 行A 行A 行B 行B 一、JOIN —— 横向拼接核心思想JOIN 用于将同一业务实体的不同维度拼在一起。两张表之间必须存在可以对齐的关联关系通常是外键把符合条件的行左右合并成一行。典型场景我有一张订单表想同时看到订单信息 下单患者的姓名。订单表和患者表之间存在patient_id关联每一条订单对应一个患者这就是典型的横向拼接场景。-- 查询订单同时展示患者姓名SELECTo.order_noAS订单号,o.amountAS金额,u.real_nameAS患者姓名FROMorders oJOINpatient_user uONo.patient_idu.idWHEREo.create_time2024-01-01结果长这样订单号 金额 患者姓名 ORDER_001 199.00 张三 ORDER_002 299.00 李四 ORDER_003 99.00 张三每一行都是一条订单 这条订单对应的患者数据是横向扩展的列变多了行数不变或者因为匹配关系有所变化。JOIN 的几种类型-- INNER JOIN内连接只返回两边都能匹配上的行SELECT*FROMAINNERJOINBONA.idB.a_id-- LEFT JOIN左连接左表全返回右表没匹配到的填 NULLSELECT*FROMALEFTJOINBONA.idB.a_id-- RIGHT JOIN右连接右表全返回左表没匹配到的填 NULLSELECT*FROMARIGHTJOINBONA.idB.a_id记忆口诀JOIN 是找对象两行数据牵手合并成一行牵手的条件就是ON后面的关联字段。 二、UNION —— 纵向堆叠核心思想UNION 用于将结构相同、但来源不同的数据集纵向堆叠在一起。两个查询的列数和数据类型必须一致把多个查询的结果上下拼成一张更长的表。典型场景我有体重日常记录表和 InBody 专业测量表想在趋势图里把两边的体重数据按时间顺序展示在同一条折线上。这两张表的记录之间没有对应关系体重记录表有365条InBody表有12条它们都是独立的测量事件。我需要的是把它们纵向堆叠按时间排列-- 体重趋势图把两张表的数据纵向合并SELECTrecord_time,weight,日常测量ASsourceFROMpatient_weight_recordWHEREpatient_id1UNIONALLSELECTrecord_time,weight,InBody测量ASsourceFROMpatient_body_compositionWHEREpatient_id1ORDERBYrecord_time结果长这样record_time weight source 2024-01-01 07:00 85.50 日常测量 2024-01-05 09:00 85.20 日常测量 2024-01-10 10:00 84.80 InBody测量 ← 来自另一张表 2024-01-15 07:30 84.50 日常测量 2024-01-20 08:00 84.10 日常测量 2024-02-10 10:00 83.60 InBody测量 ← 来自另一张表数据是纵向扩展的列数不变行数变多了。UNION 和 UNION ALL 的区别-- UNION自动去重性能较差需要额外排序去重SELECTnameFROMtable_aUNIONSELECTnameFROMtable_b-- UNION ALL不去重直接合并性能更好SELECTnameFROMtable_aUNIONALLSELECTnameFROMtable_b⚠️原则如果你确定两个结果集不会有重复数据或者你不在乎重复优先用 UNION ALL性能更好。只有在明确需要去重时才用 UNION。⚖️ 三、核心对比对比维度JOINUNION 合并方向横向列变多纵向行变多 前提条件两表有关联字段两个查询列数和类型一致 结果形态行数取决于匹配关系行数 两个查询结果之和 适用场景同一实体的不同维度同类数据的不同来源 关键字ON指定关联条件无需关联条件⚡ 典型用法订单 用户信息多个来源的同类数据合并 四、如何判断用哪个遇到把两张表合在一起的需求时问自己两个问题问题一我想要的结果列数是变多了还是行数变多了列变多 → JOIN行变多 → UNION。问题二两张表的数据是同一件事的不同角度还是同类事情的不同来源同一件事的不同角度一条订单 这条订单的用户名 → JOIN横向拼接 同类事情的不同来源体脂秤的体重记录 InBody的体重记录 → UNION纵向堆叠实际案例判断练习❓ 查询患者信息同时展示主管医生的姓名 → 患者表 JOIN 医生表同一患者档案的不同维度✅ JOIN ❓ 查询本月所有健康指标的预警记录血压预警 血糖预警 体重预警分别在不同表 → 三张预警表纵向合并同类事件的不同来源✅ UNION ALL ❓ 查询运动记录同时展示当天的饮食热量 → 运动表 LEFT JOIN 饮食表同一天的不同健康维度✅ JOIN ❓ 查询某患者所有沟通记录患者发的 医生发的 系统消息 → 这个其实在同一张表里按 sender_type 区分不需要 UNION 五、常见误区❌ 误区一以为 JOIN 可以代替 UNION-- ❌ 错误思路用 JOIN 合并两张体重表SELECTw.record_time,w.weight,b.weightFROMpatient_weight_record wJOINpatient_body_composition bONw.patient_idb.patient_id-- 结果是笛卡尔积365条 × 12条 4380条完全错误两张表没有行级别的对应关系JOIN 会产生笛卡尔积结果毫无意义。❌ 误区二UNION 的列不对齐-- ❌ 错误两个查询列数不一致SELECTrecord_time,weightFROMpatient_weight_recordUNIONALLSELECTrecord_time,weight,bmiFROMpatient_body_composition-- 报错列数不匹配-- ✅ 正确列数和类型对齐缺少的列用 NULL 补位SELECTrecord_time,weight,NULLASbmiFROMpatient_weight_recordUNIONALLSELECTrecord_time,weight,bmiFROMpatient_body_composition❌ 误区三UNION 后忘记加 ORDER BY-- ⚠️ 注意ORDER BY 要放在最后对整体结果排序SELECTrecord_time,weightFROMpatient_weight_recordWHEREpatient_id1UNIONALLSELECTrecord_time,weightFROMpatient_body_compositionWHEREpatient_id1ORDERBYrecord_time-- ✅ 放在最后对合并后的全部结果排序 六、一句话总结JOIN 是找对象两行数据牵手变成一行列变多UNION 是排队两批数据排成一队行变多。搞清楚你要的是更宽的表还是更长的表就知道该用哪个了。— END — 如有帮助欢迎点赞 收藏 ⭐ 评论 —