班次:
EmpNo YYMMDD GO1 OUT1 GO2 OUT2
048901 2013-09-01 NULL NULL NULL NULL
048901 2013-09-02 08:30 12:00 13:00 17:30048901 2013-09-04 08:40 12:10 13:10 17:40
048901 2013-09-05 08:40 12:10 13:10 17:40打卡记录:
EmpNo CardTime
048901 2013-09-02 08:25
048901 2013-09-02 08:29
048901 2013-09-02 12:12
048901 2013-09-02 12:28
048901 2013-09-02 17:28
048901 2013-09-02 17:35048901 2013-09-03 08:30
048901 2013-09-03 12:15
048901 2013-09-03 12:50
048901 2013-09-03 17:45048901 2013-09-04 08:35
048901 2013-09-04 12:35
048901 2013-09-04 12:50
048901 2013-09-04 17:45048901 2013-09-05 08:35
048901 2013-09-05 12:35
048901 2013-09-05 12:50
048901 2013-09-05 17:45048901 2013-09-05 17:56
048901 2013-09-05 21:05打卡记录10分钟内取第一条记录,如果在班次中间(12:00-13:00)只有一条打卡记录,打卡记录离班次哪个时间点较近算哪个班次点的打卡记录。如有迟到、早退优先算作迟到或早退卡。
班次时间为null、没有当天的排班或者在班次外的打卡均算休息时间,考勤结果均算为加班(无排班情况下(周末或者节假日)加班一天最多只能算8小时,有排班(平时)一天最多只能算3小时加班)最后需要能算出:
1、是否考勤异常;
2、迟到xx分钟
3、早退xx分钟
4、考勤工时:xx小时
5、加班时长:xx小时根据以上规则得到的结果为:
员工[048901]2013-09-02考勤异常;早退2分钟;迟到0分钟;考勤工时:7.96小时;加班时长:0小时
员工[048901]2013-09-03考勤正常;早退0分钟;迟到0分钟;考勤工时:0.00小时;加班时长:8小时
员工[048901]2013-09-04考勤正常;早退0分钟;迟到0分钟;考勤工时:8.00小时;加班时长:0小时
员工[048901]2013-09-05考勤正常;早退0分钟;迟到0分钟;考勤工时:8.00小时;加班时长:3小时
以上问题可以用MS SQL存储过程计算也可以用java计算,能提供一些思路也好考勤计算、打卡记录ms sqljava存储
EmpNo YYMMDD GO1 OUT1 GO2 OUT2
048901 2013-09-01 NULL NULL NULL NULL
048901 2013-09-02 08:30 12:00 13:00 17:30048901 2013-09-04 08:40 12:10 13:10 17:40
048901 2013-09-05 08:40 12:10 13:10 17:40打卡记录:
EmpNo CardTime
048901 2013-09-02 08:25
048901 2013-09-02 08:29
048901 2013-09-02 12:12
048901 2013-09-02 12:28
048901 2013-09-02 17:28
048901 2013-09-02 17:35048901 2013-09-03 08:30
048901 2013-09-03 12:15
048901 2013-09-03 12:50
048901 2013-09-03 17:45048901 2013-09-04 08:35
048901 2013-09-04 12:35
048901 2013-09-04 12:50
048901 2013-09-04 17:45048901 2013-09-05 08:35
048901 2013-09-05 12:35
048901 2013-09-05 12:50
048901 2013-09-05 17:45048901 2013-09-05 17:56
048901 2013-09-05 21:05打卡记录10分钟内取第一条记录,如果在班次中间(12:00-13:00)只有一条打卡记录,打卡记录离班次哪个时间点较近算哪个班次点的打卡记录。如有迟到、早退优先算作迟到或早退卡。
班次时间为null、没有当天的排班或者在班次外的打卡均算休息时间,考勤结果均算为加班(无排班情况下(周末或者节假日)加班一天最多只能算8小时,有排班(平时)一天最多只能算3小时加班)最后需要能算出:
1、是否考勤异常;
2、迟到xx分钟
3、早退xx分钟
4、考勤工时:xx小时
5、加班时长:xx小时根据以上规则得到的结果为:
员工[048901]2013-09-02考勤异常;早退2分钟;迟到0分钟;考勤工时:7.96小时;加班时长:0小时
员工[048901]2013-09-03考勤正常;早退0分钟;迟到0分钟;考勤工时:0.00小时;加班时长:8小时
员工[048901]2013-09-04考勤正常;早退0分钟;迟到0分钟;考勤工时:8.00小时;加班时长:0小时
员工[048901]2013-09-05考勤正常;早退0分钟;迟到0分钟;考勤工时:8.00小时;加班时长:3小时
以上问题可以用MS SQL存储过程计算也可以用java计算,能提供一些思路也好考勤计算、打卡记录ms sqljava存储
写SP是正道,毕竟是以集(SETS)方式处理,性能良好
可能还有调班、请假、上半天班等各种情况
我的SP是几百行代码
/*
EmpNo YYMMDD GO1 OUT1 GO2 OUT2
---------- --------------- ---------- ---------- ---------- ----------
048901 2013-09-01 NULL NULL NULL NULL
048901 2013-09-02 08:30 12:00 13:00 17:30
048901 2013-09-03 08:30 12:00 13:00 17:30
048901 2013-09-04 08:40 12:10 13:10 17:40
048901 2013-09-05 08:40 12:10 13:10 17:40(5 row(s) affected)
*/select * from 打卡记录
/*
EmpNo CardTime
---------- ------------------------------
048901 2013-09-02 08:25
048901 2013-09-02 08:29
048901 2013-09-02 12:12
048901 2013-09-02 12:28
048901 2013-09-02 17:28
048901 2013-09-02 17:35
048901 2013-09-03 08:30
048901 2013-09-03 12:15
048901 2013-09-03 12:50
048901 2013-09-03 17:45
048901 2013-09-04 08:35
048901 2013-09-04 12:35
048901 2013-09-04 12:50
048901 2013-09-04 17:45
048901 2013-09-05 08:35
048901 2013-09-05 12:35
048901 2013-09-05 12:50
048901 2013-09-05 17:45
048901 2013-09-05 17:56
048901 2013-09-05 21:05(20 row(s) affected)
*/
select EmpNo,
cast(YYMMDD as date) 'CardDate',
cast(YYMMDD+' '+GO1 as datetime) 'GO1',
cast(YYMMDD+' '+OUT1 as datetime) 'OUT1',
cast(YYMMDD+' '+GO2 as datetime) 'GO2',
cast(YYMMDD+' '+OUT2 as datetime) 'OUT2'
into #t1
from 班次
where GO1 is not null and OUT1 is not null
and GO2 is not null and OUT2 is not null;with t as
(select EmpNo,
cast(CardTime as date) 'CardDate',
cast(CardTime as datetime) 'CardTime',
row_number() over(partition by cast(CardTime as date) order by cast(CardTime as datetime)) 'rn'
from 打卡记录)
select a.EmpNo,a.CardDate,a.CardTime,row_number() over(partition by a.CardDate order by a.CardTime) 'rn'
into #t2
from t a
left join t b on a.EmpNo=b.EmpNo and a.CardDate=b.CardDate and a.rn=b.rn+1
where datediff(mi,b.CardTime,a.CardTime)>10 or b.rn is nullselect a.EmpNo,a.CardDate,
(select case when datediff(mi,b.CardTime,a.OUT1)>0 then datediff(mi,b.CardTime,a.OUT1) else 0 end
from #t2 b
where b.EmpNo=a.EmpNo and b.CardDate=a.CardDate and b.rn=2)+
(select case when datediff(mi,b.CardTime,a.OUT2)>0 then datediff(mi,b.CardTime,a.OUT2) else 0 end
from #t2 b
where b.EmpNo=a.EmpNo and b.CardDate=a.CardDate and b.rn=4) 'leaveearly',
(select case when datediff(mi,a.GO1,b.CardTime)>0 then datediff(mi,a.GO1,b.CardTime) else 0 end
from #t2 b
where b.EmpNo=a.EmpNo and b.CardDate=a.CardDate and b.rn=1)+
(select case when datediff(mi,a.GO2,b.CardTime)>0 then datediff(mi,a.GO2,b.CardTime) else 0 end
from #t2 b
where b.EmpNo=a.EmpNo and b.CardDate=a.CardDate and b.rn=3) 'late',
datediff(mi,a.OUT2,(select top 1 b.CardTime
from #t2 b where b.EmpNo=a.EmpNo and b.CardDate=a.CardDate order by b.rn desc))/60 'ot'
into #t3
from #t1 a
select '员工['+a.EmpNo+']'+convert(varchar,a.CardDate,23)+'考勤'
+case when a.leaveearly=0 and a.late=0 then '正常;' else '异常;' end
+'早退'+rtrim(a.leaveearly)+'分钟;'
+'迟到'+rtrim(a.late)+'分钟;'
+'考勤工时'+rtrim(convert(decimal(4,2),(8*60-a.leaveearly-a.late)/60.00))+'小时;'
+'加班时长'+rtrim(a.ot)+'小时' 'r'
from #t3 a/*
r
---------------------------------------------------------------------------------
员工[048901]2013-09-02考勤异常;早退2分钟;迟到0分钟;考勤工时7.97小时;加班时长0小时
员工[048901]2013-09-03考勤正常;早退0分钟;迟到0分钟;考勤工时8.00小时;加班时长0小时
员工[048901]2013-09-04考勤正常;早退0分钟;迟到0分钟;考勤工时8.00小时;加班时长0小时
员工[048901]2013-09-05考勤正常;早退0分钟;迟到0分钟;考勤工时8.00小时;加班时长3小时(4 row(s) affected)
*/
程序代码的思维,呵,无SETS概念
如果有几千人(偶企业一万五),够你算的。