联结查询与聚合:跨越多表提取洞察


文档摘要

联结查询与聚合:跨越多表提取洞察 关系型数据库的精华在于「数据分散在多张表,查询时再灵活组合」。本节讲解 JOIN(联结)与 GROUP BY(分组聚合),它们让你能从分离的表中提取出整合的、统计性的信息。 为什么需要联结 回忆第 2 章:订单表只存了 ,并不存用户的邮箱和昵称。当你要展示「这笔订单是谁下的、叫什么名字」时,就需要把订单表和用户表「按 userid 对应起来」合并查询——这就是联结(JOIN)。 JOIN 的基本写法 JOIN 通过两张表之间的关联条件,把它们的行拼接到一起。 这条查询的含义是:从订单表出发,按 把对应的用户行匹配过来,最终输出订单号、用户邮箱、金额。 JOIN 的几种类型 INNER JOIN(内联结,等价于 JOIN):只保留两表中能匹配上的行。

联结查询与聚合:跨越多表提取洞察

关系型数据库的精华在于「数据分散在多张表,查询时再灵活组合」。本节讲解 JOIN(联结)与 GROUP BY(分组聚合),它们让你能从分离的表中提取出整合的、统计性的信息。

为什么需要联结

回忆第 2 章:订单表只存了 user_id,并不存用户的邮箱和昵称。当你要展示「这笔订单是谁下的、叫什么名字」时,就需要把订单表和用户表「按 user_id 对应起来」合并查询——这就是联结(JOIN)。

JOIN 的基本写法

JOIN 通过两张表之间的关联条件,把它们的行拼接到一起。

SELECT orders.id, users.email, orders.amount FROM orders JOIN users ON orders.user_id = users.id WHERE orders.status = 'paid';

这条查询的含义是:从订单表出发,按 orders.user_id = users.id 把对应的用户行匹配过来,最终输出订单号、用户邮箱、金额。

JOIN 的几种类型

  • INNER JOIN(内联结,等价于 JOIN):只保留两表中能匹配上的行。上例即内联结。
  • LEFT JOIN(左联结):保留左表所有行;右表匹配不上的,对应字段为空。常用于「列出所有订单,即使某些订单的用户已被删除」。
  • RIGHT JOIN(右联结):与左联结对称,保留右表所有行。
  • FULL JOIN(全联结):保留两表所有行,匹配不上的字段为空。

实践中最常用的是 INNER JOIN 和 LEFT JOIN。下表用订单与用户的例子概括它们的差别:

联结类型 一笔订单对应的用户不存在时 结果倾向
INNER JOIN 该订单被丢弃 只要匹配的
LEFT JOIN 订单保留,用户字段为空 以订单为主

联结多张表

一条查询可以联结不止两张表。例如查询「某订单中包含哪些商品及其数量」:

SELECT orders.id, products.name, order_items.quantity FROM orders JOIN order_items ON orders.id = order_items.order_id JOIN products ON order_items.product_id = products.id WHERE orders.id = '某订单ID';

联结多表的关键是理清「关联条件链」:订单↔订单项↔商品,每一步通过外键对应起来。

用 GROUP BY 分组

GROUP BY 把行按某列(或某些列)的值分组,每组再进行统计。典型问题:「每个用户下了多少笔订单、总金额多少?」

SELECT user_id, COUNT(*) AS order_count, SUM(amount) AS total FROM orders GROUP BY user_id;

这条查询把订单按 user_id 分组,每组计算订单数(COUNT)和总金额(SUM)。

常用聚合函数

聚合函数对一组值进行计算并返回单个结果:

  • COUNT(*):行数。
  • SUM(列):求和。
  • AVG(列):平均值。
  • MAX(列) / MIN(列):最大值 / 最小值。

聚合常与分组配合使用;不加 GROUP BY 时,聚合函数作用于整个结果集(如「全表总订单数」)。

用 HAVING 过滤分组

WHERE 用于过滤「行」,而 HAVING 用于过滤「分组」,通常接在 GROUP BY 之后。例如「只看下单超过 5 次的用户」:

SELECT user_id, COUNT(*) AS order_count FROM orders GROUP BY user_id HAVING COUNT(*) > 5;

记忆口诀:WHERE 在分组前过滤行,HAVING 在分组后过滤组。

子查询

子查询是「查询里的查询」,能把一个查询的结果作为另一个查询的输入。例如「下单金额高于平均值的订单」:

SELECT id, amount FROM orders WHERE amount > (SELECT AVG(amount) FROM orders);

子查询还常用于 IN、EXISTS 等场景,是表达复杂逻辑的灵活工具。

联结与聚合的性能

联结和聚合是查询中较重的操作,几个优化要点:

  • 联接的关联列(外键与对应主键)应有索引,否则会退化为全表两两比对。
  • 分组列也应有索引支持,尤其是大表分组。
  • 避免对大结果集做无谓的 ORDER BY + OFFSET,能先过滤就先过滤。
  • 复杂查询同样用 EXPLAIN 检查执行计划。

联结 + 聚合的典型场景

把两者结合,能回答绝大多数业务统计问题:

  • 每个分类下商品数量与平均价格(商品 JOIN 分类,GROUP BY 分类)。
  • 最近 7 天每天的订单总额(按日期 GROUP BY + SUM)。
  • 购买过某商品的用户名单(订单项 JOIN 订单 JOIN 用户,WHERE 商品)。
  • 销量前十的商品(订单项 GROUP BY 商品,SUM 数量,ORDER BY + LIMIT)。

小结

JOIN 把分散在多表的行拼接成完整视图,GROUP BY 与聚合函数把行汇总成统计洞察——它们共同构成了关系型数据库「整合信息」的核心能力。掌握联结与聚合,你就能从数据中提取任意维度的洞察。下一节进入数据库自动化:用视图、函数与触发器把重复逻辑固化下来。


发布者: 作者: 灏天文库 转发
评论区 (0)
U