4. group by 和聚合函数怎么用于测试?
group by 和聚合函数是测试报表、后台看板、列表统计、运营数据时最常用的 SQL 能力。很多测试同学平时只会查单条数据,一遇到“今日订单数”“各状态工单数”“每个用户消费金额”“每个部门审批数量”“活动报名人数”这类统计需求,就不知道怎么验证,只能相信页面显示。这会导致统计类 Bug 很容易漏掉。
统计类功能在企业系统里非常重要。老板看销售额,运营看转化率,客服看工单量,财务看支付金额,管理者看审批效率。这些数据一旦错误,影响的不只是页面展示,而是业务决策。因此测试人员必须掌握基本聚合查询,能用 SQL 复算页面数字。
一、聚合函数解决什么问题
聚合函数不是用来查某一条数据,而是用来把多条数据汇总成一个结果。常见聚合函数包括:
count:统计数量;sum:求和;avg:求平均值;max:求最大值;min:求最小值。
如果不配合 group by,聚合函数通常对整个结果集统计。如果配合 group by,就可以按某个维度分组统计。
例如统计所有已支付订单金额:
select sum(pay_amount)
from t_pay_record
where pay_status = 'SUCCESS';
按日期统计每天支付金额:
select date(pay_time) as pay_date, sum(pay_amount) as total_amount
from t_pay_record
where pay_status = 'SUCCESS'
group by date(pay_time)
order by pay_date desc;
这就是从“总数”到“分组统计”的区别。
二、测试中最常见的统计场景
1. 按状态统计数量
后台经常展示不同状态订单数、工单数、审批数。例如订单状态统计:
select status, count(*) as order_count
from t_order
group by status;
如果页面显示待支付 10、已支付 20、已取消 5,你就可以用这条 SQL 复核。
2. 按日期统计趋势
日报、周报、趋势图经常按日期聚合:
select date(create_time) as order_date, count(*) as order_count
from t_order
where create_time >= '2026-04-01 00:00:00'
and create_time < '2026-05-01 00:00:00'
group by date(create_time)
order by order_date;
测试时要特别关注时间范围是否包含边界数据。
3. 按用户统计消费金额
会员系统、商城系统经常统计用户消费金额:
select user_id, sum(total_amount) as total_consume
from t_order
where status = 'PAID'
group by user_id
order by total_consume desc;
如果页面有“消费排行榜”,这类 SQL 就能用于验证。
4. 按部门统计审批数量
OA 系统经常按部门统计审批单:
select department_id, count(*) as approval_count
from t_approval
where status = 'APPROVED'
group by department_id;
如果还要展示部门名称,就需要关联部门表。
5. 统计去重用户数
活动统计里经常要统计参与用户数,而不是参与记录数。如果一个用户可以报名多次,应该用 count(distinct user_id)。
select count(distinct user_id) as user_count
from t_activity_record
where activity_id = 1001;
这是报表测试里非常容易出错的地方。
三、group by 的核心理解
group by 的意思是按某个字段或表达式把数据分组,然后对每组进行聚合。比如按订单状态分组,每个状态就是一组;按日期分组,每一天就是一组;按用户分组,每个用户就是一组。
一个常见规则是:select 中出现的非聚合字段,通常要出现在 group by 中。
select status, count(*)
from t_order
group by status;
这里 status 是分组字段,count(*) 是聚合结果。
如果你写:
select status, order_no, count(*)
from t_order
group by status;
这个 SQL 在一些数据库模式下可能报错,或者结果不可靠,因为 order_no 不是聚合字段,也不是分组字段。面试时如果能说出这一点,会体现你不是只会抄 SQL。
四、where 和 having 的区别
这是面试高频问题。
where:分组前过滤原始数据;having:分组后过滤聚合结果。
例如统计每个用户已支付订单数:
select user_id, count(*) as order_count
from t_order
where status = 'PAID'
group by user_id;
如果只看订单数大于 3 的用户:
select user_id, count(*) as order_count
from t_order
where status = 'PAID'
group by user_id
having count(*) > 3;
status = 'PAID' 是原始数据过滤,所以放 where;count(*) > 3 是聚合后的结果过滤,所以放 having。
五、统计类功能最容易出错的地方
1. 时间范围错误
这是报表 Bug 第一高发点。比如页面选择 4 月 30 日,后端 SQL 写成:
where create_time <= '2026-04-30 23:59:59'
如果数据库有毫秒,23:59:59.500 可能被遗漏。更稳妥写法是:
where create_time >= '2026-04-30 00:00:00'
and create_time < '2026-05-01 00:00:00'
2. 状态条件漏掉
统计支付金额时,只能统计成功支付,不能把待支付、已取消、退款订单算进去。
select sum(total_amount)
from t_order
where status = 'PAID';
如果漏了状态条件,金额会虚高。
3. 重复数据被统计
一对多关联后,订单可能被明细表放大。例如订单主表关联明细表后,一笔订单三个商品会出现三行。如果统计订单数,要用:
count(distinct o.order_no)
而不是直接 count(*)。
4. 逻辑删除数据被统计
很多表有 is_deleted 字段。页面只统计有效数据,SQL 如果没加 is_deleted = 0,结果会偏大。
5. 退款和取消场景没处理
统计销售额时,要明确是否扣除退款金额。统计订单数时,要明确取消订单是否计入。需求没说清楚时,测试要主动问。
六、完整案例:后台首页数据看板测试
假设后台首页展示:今日订单数、今日支付金额、待处理工单数、近 7 天订单趋势。
今日订单数
select count(*)
from t_order
where create_time >= '2026-04-30 00:00:00'
and create_time < '2026-05-01 00:00:00';
今日支付金额
select sum(pay_amount)
from t_pay_record
where pay_status = 'SUCCESS'
and pay_time >= '2026-04-30 00:00:00'
and pay_time < '2026-05-01 00:00:00';
待处理工单数
select count(*)
from t_ticket
where status in ('WAIT_HANDLE', 'HANDLING')
and is_deleted = 0;
近 7 天订单趋势
select date(create_time) as order_date, count(*) as order_count
from t_order
where create_time >= '2026-04-24 00:00:00'
and create_time < '2026-05-01 00:00:00'
group by date(create_time)
order by order_date;
测试时不仅要验证数字是否一致,还要验证无数据日期是否展示为 0、日期排序是否正确、时区是否一致。
七、面试回答模板
如果面试官问“group by 和聚合函数在测试中怎么用”,可以这样答:
我主要在报表、看板和列表统计中使用 group by 和聚合函数。比如后台展示今日订单数、支付金额、各状态订单数量时,我会用 count、sum、group by 按状态、日期或用户维度复算页面数据。测试时我会特别关注时间范围、状态过滤、逻辑删除、重复数据和退款取消场景。比如统计今日支付金额,我不会直接 sum 订单金额,而会限定支付成功状态和当天支付时间范围,必要时还要扣除退款金额。
八、面试追问
追问:where 和 having 区别?
where 是分组前过滤原始数据,having 是分组后过滤聚合结果。比如筛选已支付订单用 where,筛选订单数大于 3 的用户用 having。
追问:count(*) 和 count(distinct user_id) 区别?
count(*) 统计记录数,count(distinct user_id) 统计去重用户数。活动参与记录数和参与用户数不是一回事。
追问:报表数字和 SQL 查出来不一致怎么办?
先确认口径,包括时间范围、状态条件、是否去重、是否包含退款、是否过滤逻辑删除、是否有缓存或异步统计。再对比接口返回和数据库数据。
九、练习清单
- 统计每种订单状态数量;
- 统计今日支付成功金额;
- 按日期统计最近 7 天订单数;
- 统计每个用户消费金额;
- 查询订单数大于 3 的用户;
- 统计活动参与记录数和参与用户数;
- 统计每个商品销量;
- 统计每个部门审批数量;
- 找出支付金额最高的一天;
- 验证后台看板 4 个指标。
聚合查询的核心是“统计口径”。面试中你不仅要会写 SQL,更要能说清楚为什么这么统计、哪些数据应该算、哪些数据不应该算。这样才像真正测过报表的人。
配套刷题:

