联结查询与聚合:跨越多表提取洞察 关系型数据库的精华在于「数据分散在多张表,查询时再灵活组合」。本节讲解 JOIN(联结)与 GROUP BY(分组聚合),它们让你能从分离的表中提取出整合的、统计性的信息。 为什么需要联结 回忆第 2 章:订单表只存了 ,并不存用户的邮箱和昵称。当你要展示「这笔订单是谁下的、叫什么名字」时,就需要把订单表和用户表「按 userid 对应起来」合并查询——这就是联结(JOIN)。 JOIN 的基本写法 JOIN 通过两张表之间的关联条件,把它们的行拼接到一起。 这条查询的含义是:从订单表出发,按 把对应的用户行匹配过来,最终输出订单号、用户邮箱、金额。 JOIN 的几种类型 INNER JOIN(内联结,等价于 JOIN):只保留两表中能匹配上的行。
关系型数据库的精华在于「数据分散在多张表,查询时再灵活组合」。本节讲解 JOIN(联结)与 GROUP BY(分组聚合),它们让你能从分离的表中提取出整合的、统计性的信息。
回忆第 2 章:订单表只存了 user_id,并不存用户的邮箱和昵称。当你要展示「这笔订单是谁下的、叫什么名字」时,就需要把订单表和用户表「按 user_id 对应起来」合并查询——这就是联结(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 把对应的用户行匹配过来,最终输出订单号、用户邮箱、金额。
实践中最常用的是 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 把行按某列(或某些列)的值分组,每组再进行统计。典型问题:「每个用户下了多少笔订单、总金额多少?」
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 时,聚合函数作用于整个结果集(如「全表总订单数」)。
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 等场景,是表达复杂逻辑的灵活工具。
联结和聚合是查询中较重的操作,几个优化要点:
把两者结合,能回答绝大多数业务统计问题:
JOIN 把分散在多表的行拼接成完整视图,GROUP BY 与聚合函数把行汇总成统计洞察——它们共同构成了关系型数据库「整合信息」的核心能力。掌握联结与聚合,你就能从数据中提取任意维度的洞察。下一节进入数据库自动化:用视图、函数与触发器把重复逻辑固化下来。