在 SQL 面试中,多表查询 + 业务场景统计 是高频考点。常见的题目之一就是:
已知用户表(user)、订单表(order),如何统计每个用户的订单数量和总金额?
这类问题不仅考察语法掌握,还考察你对业务逻辑的抽象与 SQL 优化能力。本文带你逐步解析。
一、题目背景
假设有两张表:
用户表:存储用户的基本信息(用户 id、姓名等)。
订单表:存储订单详情(订单 id、用户 id、订单金额等)。
需求:查询每个用户的订单数和订单总金额。
二、解法思路
明确关联关系
用户表和订单表是一对多关系。
需要通过 user.id = order.user_id 进行关联。
选择合适的 JOIN
如果只统计有订单的用户,用 INNER JOIN。
如果希望统计所有用户,即使没有订单也显示,用 LEFT JOIN。
用聚合函数做统计
COUNT 统计订单数量。
SUM 统计订单金额。
搭配 GROUP BY 按用户分组。
三、SQL 实现
- 仅统计有订单的用户
COUNT(o.id) AS order_count,
SUM(o.amount) AS total_amount
FROM user u
INNER JOIN orders o ON u.id = o.user_id
- 包含所有用户(无订单显示为 0)
COUNT(o.id) AS order_count,
IFNULL(SUM(o.amount), 0) AS total_amount
FROM user u
LEFT JOIN orders o ON u.id = o.user_id
IFNULL 的作用是防止出现 NULL,比如用户没有订单时总金额为 0。
四、面试延伸问题
在实际面试中,考官往往会追问:
如何统计近 30 天的订单?
WHERE o.order_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
如何只统计已支付的订单?
WHERE o.status = 'paid'
如果要统计订单均价呢?
AVG(o.amount)
能否只显示订单数大于 5 的用户?
HAVING COUNT(o.id) > 5
五、优化思路
建立索引
在 orders.user_id 上加索引,加快关联查询。
在 orders.order_date 上加索引,加快时间区间过滤。
避免不必要的函数
尽量不要在 WHERE 条件里对字段直接用函数,否则索引失效。
大数据量时分批查询
如果订单数据量非常大,可以用分页或分区表。
六、总结
这类题目考察三个核心点:
多表关联: INNER JOIN vs LEFT JOIN。
聚合统计: COUNT / SUM / AVG 等函数结合 GROUP BY。
业务扩展: 加上时间区间、订单状态、HAVING 过滤。
一句话记住面试答题思路:
先确定表关系,再选 JOIN 类型,用聚合函数统计,最后考虑边界情况(无订单用户、NULL 值、条件过滤)。