SQL查询错误排查:员工按时/提前到岗数量统计结果异常
首先,你的SQL返回异常大的结果(441),核心原因是错误地使用了LEFT JOIN关联两个打卡表,外加一些逻辑细节错误,下面一步步拆解:
1. 表关联方式完全错误
你用LEFT JOIN CHECKEXACT bf ON af.USERID = bf.USERID来关联两个表,这会产生笛卡尔积:因为CHECKINOUT里的39条USERID=1040的记录,每条都会和CHECKEXACT里的1条USERID=1040的记录匹配,得到39条组合记录。但你的需求是统计所有有效打卡(包括CHECKINOUT的正常打卡和CHECKEXACT的补录打卡),正确的做法应该是用UNION ALL把两个表的记录合并,而不是关联它们——关联是用来匹配关联数据的,合并才是用来把同类型的记录放在一起统计的。
2. WeekDay函数的逻辑错误
在Access SQL中,WeekDay函数默认以周日为1(vbSunday),所以:
- 周日=1,周一=2,...,周五=6,周六=7
你写的WeekDay(DateValue(af.CHECKTIME)) <> 6是在排除周五,而不是你想要的周六。如果要排除周六,应该写成WeekDay(DateValue(af.CHECKTIME)) <> 7。
3. 条件判断可以简化
你的嵌套IIf写法不仅冗余,还容易出错,可以用一个更清晰的逻辑:如果不是周六且打卡时间≤08:15,或者打卡时间≤08:30(不管是否周六),都算按时/提前到岗。
修复后的SQL
下面是修正后的查询语句,它会正确合并两个表的打卡记录,然后统计符合条件的数量:
SELECT USERID, SUM( IIf( (WeekDay(DateValue(CHECKTIME)) <> 7 AND Format(CHECKTIME, 'hh:nn:ss') <= '08:15:00') OR Format(CHECKTIME, 'hh:nn:ss') <= '08:30:00', 1, 0 ) ) AS [Came On Time or Early] FROM ( -- 合并正常打卡和补录打卡记录 SELECT USERID, CHECKTIME FROM CHECKINOUT UNION ALL SELECT USERID, CHECKTIME FROM CHECKEXACT ) AS CombinedRecords WHERE USERID = 1040 AND CHECKTIME Between #3/1/2020# And #3/31/2020# GROUP BY USERID
为什么原查询返回441?
结合你的数据量(39条CHECKINOUT + 1条CHECKEXACT),原查询的笛卡尔积导致39条组合记录,但441这个结果说明可能你的CHECKEXACT表中实际存在多条USERID=1040的记录(比如11条,39×11=429,接近441),或者你的条件判断逻辑错误导致所有记录都返回1,再加上重复统计。但无论如何,修复关联方式和逻辑后,就能得到正确的结果。
内容的提问来源于stack exchange,提问作者Dont Bullying Me

