跨表统计需先明确主表(结果分组依据)与从表(提供聚合字段),再据空值需求选JOIN类型;如统计各部门员工数及平均薪资,应以dept为主表LEFT JOIN emp,GROUP BY主表非聚合字段,并注意COUNT与AVG对NULL的处理差异。

跨表统计的核心不是堆函数,而是理清表间关系再选连接方式。先确认主表、从表,再看统计维度落在哪张表,最后决定用 JOIN 还是子查询——多数场景 JOIN 更直观高效。
明确主表和统计目标,避免“从哪查起”混乱
比如要统计“每个部门的员工数和平均薪资”,部门信息在 dept 表,员工信息在 emp 表,那 dept 就是主表(结果要按部门展示),emp 是从表(提供人数、薪资数据)。不能反过来以 emp 为主表再 group by dept_id,否则没员工的部门会被漏掉。
- 主表 = 最终结果按哪一列分组(如 dept.name)
- 从表 = 提供被聚合字段(如 emp.salary、count(*))
- 空值敏感场景(如查“所有部门+员工数”),主表必须是 dept,用 LEFT JOIN emp
JOIN 类型选对,结果才不丢不重
继续上面的例子:如果用 INNER JOIN,部门没员工就不出现在结果里;用 LEFT JOIN,空部门也会显示 0 人、NULL 平均薪资。实际写法:
SELECT d.name, COUNT(e.id) AS emp_cnt, ROUND(AVG(e.salary), 2) AS avg_sal
FROM dept d
LEFT JOIN emp e ON d.id = e.dept_id
GROUP BY d.id, d.name;
- COUNT(e.id) 自动忽略 NULL,空部门计为 0
- AVG(e.salary) 对空部门返回 NULL,可加 COALESCE(AVG(e.salary), 0) 转成 0
- GROUP BY 必须包含主表所有非聚合字段(d.id 和 d.name 都要写)
多层关联+条件过滤,拆开想比硬写更稳
再进阶:查“每个城市中,2023年入职且薪资超8000的员工所在部门的平均薪资”。涉及 city(来自 dept)、emp 入职时间、薪资、部门平均薪资——四层逻辑:
- 先筛出 2023 年入职且 salary > 8000 的员工(子查询 or WHERE)
- 关联 dept 拿到 city 和 dept_id
- 再按 city + dept_id 分组算部门平均薪资(注意:不是全公司平均)
- 最后按 city 汇总(如求各城市最高部门均薪)
推荐分步写:先写带 WHERE 的基础 JOIN 查出目标员工+部门+城市,再套一层 GROUP BY city, dept_id,外层再聚合。比单条嵌套三层子查询更易调试。
别忽略 NULL 和去重,统计值才真实
常见坑:
- COUNT(*) 统计行数,COUNT(字段) 会跳过 NULL —— 想统计“有手机号的员工数”,用 COUNT(phone)
- 员工表里一个员工可能有多条考勤记录,JOIN 后直接 COUNT(*) 会虚高 —— 加 DISTINCT 或先聚合再 JOIN
- 部门表和员工表都有 name 字段,SELECT 时必须写表别名(d.name, e.name),否则报错或混淆
基本上就这些。跨表统计不复杂但容易忽略连接语义和空值处理,动手前花两分钟画个表关系草图,比查十次语法更快。










