班次:
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存储

解决方案 »

  1.   

    写这个是比较繁琐点,很多细节(规则)要逐步完善和梳理
    写SP是正道,毕竟是以集(SETS)方式处理,性能良好
    可能还有调班、请假、上半天班等各种情况
    我的SP是几百行代码
      

  2.   

    tsp3ng 说的跟我想的有点接近,但是你说的第三点“比较出异常刷卡(迟到,早退,多刷,少刷)。”这个就比较麻烦了,还没有思路应该怎么样去做才是比较好的
      

  3.   

    建议分步骤完成,select * from 班次
    /*
    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)
    */
      

  4.   

    "一次只考勤一个员工一天的考勤"
    程序代码的思维,呵,无SETS概念
    如果有几千人(偶企业一万五),够你算的。