跨表统计需先理清业务逻辑和关联路径,明确统计目标后反推所需表及连接方式,注意数据粒度、连接类型选择与分步验证。

跨表统计不是简单拼几个表,关键在理清业务逻辑和关联路径。先想清楚“我要算什么”“数据分散在哪几张表”“它们怎么连起来”,再动手写SQL。
明确统计目标,反推需要哪些表
比如要算“每个部门的在职员工平均薪资”,就得知道:部门信息在 departments 表,员工基本信息和部门ID在 employees 表,薪资记录可能在独立的 salaries 表(尤其有历史调薪时)。不能只连 employees 和 departments 就完事——如果薪资是最新一条,还得关联 salaries 并取 MAX(from_date) 或用窗口函数去重。
- 查平均薪资 → 必须包含 salaries 表
- 按部门分组 → departments 和 employees 都要有 dept_id 字段
- “在职”通常指 emp_status = 'Active' 或 contracts.end_date > TODAY → 要检查是否有合同/状态表
选对连接方式,避免漏数或翻倍
INNER JOIN 最安全,但会丢掉没薪资记录的员工;LEFT JOIN 更稳妥,但要注意:如果 salaries 表一对多(一个员工多条薪资记录),直接 LEFT JOIN 后 COUNT(*) 就会虚高。这时候得先聚合再连接。
- 错误写法:
FROM employees e LEFT JOIN salaries s ON e.emp_id = s.emp_id→ 员工A有3条薪资记录,GROUP BY 部门后,e.name 被重复计算3次 - 推荐写法:先用子查询或 CTE 算出每人最新薪资:
SELECT emp_id, MAX(from_date) AS max_date FROM salaries GROUP BY emp_id,再连回主表 - 部门可能有无人归属的情况?那就用 departments 左连 employees,确保部门不丢
分步写 + 临时验证,别硬套大SQL
复杂统计建议拆三步走:
- 第一步:单独查出带部门名称、员工ID、最新薪资的中间结果(加 LIMIT 10 看对不对)
- 第二步:在这个结果上 GROUP BY dept_name,试 SUM(salary) / COUNT(emp_id)
- 第三步:补 WHERE 过滤在职、时间范围等条件,最后加上 ROUND(AVG(salary),2) 美化输出
这样每步可验证,出错能快速定位是关联错了,还是聚合逻辑有问题。
真实案例:销售团队季度成单额+客户数+复购率
涉及四张表:sales_team(团队ID、名称)、orders(订单ID、销售员ID、金额、下单时间)、customers(客户ID、首次下单时间)、order_items(订单明细,用于判断是否复购)。
核心难点是“复购率”= 有过≥2次下单的客户数 ÷ 总下单客户数。不能只看 orders 表的客户ID频次,得先按客户聚合下单次数,再打标是否复购,最后回连团队维度统计。
- 用 CTE 先算客户层级行为:
WITH cust_orders AS (SELECT customer_id, COUNT(*) AS order_cnt FROM orders WHERE order_date >= '2024-04-01' GROUP BY customer_id) - 再关联 sales_team:把 orders → sales_team(通过 sales_rep_id),再 LEFT JOIN cust_orders 获取每个订单对应的客户总下单次数
- 最后 SELECT 中用
COUNT(DISTINCT customer_id)算客户数,COUNT(CASE WHEN order_cnt >= 2 THEN 1 END)算复购客户数
基本上就这些。跨表统计不复杂,但容易忽略数据粒度和业务定义。写之前多问一句:“这个‘平均’是按人算,还是按订单算?这个‘复购’是以客户为单位,还是以订单为单位?”——答案决定了表怎么连、GROUP BY 写在哪、聚合函数套几层。










