如何按日汇总上尉军衔(range=7)人员的奖金金额与数量?
解决上尉军衔人员奖金按日汇总的问题
这问题的核心是要精准匹配奖金发放时用户的当前军衔——毕竟军衔是会变动的,不能直接按user_id关联就完事,得确保奖金发放的时间点,用户已经是上尉(range=7)了。结合你用的Access SQL语法,我给你整理了最贴合需求的实现方案:
完整SQL语句(通用版,支持军衔升降级)
SELECT p.user_id, Format(p.time, "Short Date") AS day, Sum(Nz(p.money, 0)) AS [Sum - money], Count(p.money) AS [Count - Payment] FROM Payment p INNER JOIN ( -- 子查询:获取每个用户在奖金发放时刻的最新军衔 SELECT u1.user_id, u1.time AS rank_time, u1.range FROM 军衔表 u1 WHERE u1.time = ( SELECT Max(u2.time) FROM 军衔表 u2 WHERE u2.user_id = u1.user_id AND u2.time <= p.time ) ) r ON p.user_id = r.user_id WHERE r.range = 7 GROUP BY p.user_id, Format(p.time, "Short Date") HAVING Count(p.money) > 0;
关键逻辑解释
- 子查询匹配当前军衔:
对于每一笔奖金记录,子查询会找到该用户所有时间早于等于奖金发放时间的军衔记录,然后取最新的那条(Max(u2.time)),这样就能准确得到奖金发放时用户的真实军衔。 - 筛选上尉人员:
通过WHERE r.range =7过滤出军衔为上尉的记录,再进入后续的汇总逻辑。 - 简化空值处理:
用Access原生的Nz函数替代你原来的IIf(IsNull(...)),功能完全一致,但写法更简洁——把NULL的奖金金额转为0,避免汇总出错。
验证示例数据
拿你给的例子来看:
- 用户
a在01.01.10 10:00的奖金,对应的最新军衔是09:00的range=7,会被计入;而00:00的奖金对应的是00:00的range=6,会被排除,所以当日汇总金额为2,和期望结果一致。 - 用户
c在04.01.10 00:00的奖金,此时他的军衔还没升到7(00:05才晋升),所以被排除;00:05的奖金对应range=7,被计入,当日汇总金额为5,符合预期。
简化版(若军衔只升不降)
如果你的业务场景中,军衔只会晋升不会降级,那可以用更简洁的EXISTS写法:
SELECT p.user_id, Format(p.time, "Short Date") AS day, Sum(Nz(p.money, 0)) AS [Sum - money], Count(p.money) AS [Count - Payment] FROM Payment p WHERE EXISTS ( SELECT 1 FROM 军衔表 u WHERE u.user_id = p.user_id AND u.time <= p.time AND u.range =7 ) GROUP BY p.user_id, Format(p.time, "Short Date") HAVING Count(p.money) > 0;
注意事项
- 记得把SQL中的
军衔表替换成你实际使用的表名; - 确保两张表的
time字段都是timestamp类型,避免时间格式匹配出错。
内容的提问来源于stack exchange,提问作者mitrik_bnr
相关产品推荐
相关产品推荐

