• 考勤问题思路和解决


    近期在做一个考勤系统,考勤主要关注的是缺勤、迟到和早退。眼下的打卡控制器能够记录username和打卡时间,用户可能一天打卡多次,也可能一天仅仅打了一次卡,这些情况都须要考虑。

    打卡信息都存储在考勤表中,从中要挖掘出一个月内的缺勤人员,迟到人员和早退人员,而且能显示缺勤、迟到和早退的时间。

    考勤表

    CREATE TABLE [dbo].[kaoqin](
    	[user_name] [varchar](50) NULL,
    	[card_time] [datetime] NULL
    ) ON [PRIMARY]
    
    GO
    

    插入測试数据

    INSERT INTO [master].[dbo].[kaoqin]
    select '张三', '2014-08-03 09:36:00'
    union all
    select '张三', '2014-08-03 18:10:00'
    union all
    select '张三', '2014-08-04 08:32:00'
    union all
    select '张三', '2014-08-04 15:15:00'
    union all
    select '张三', '2014-08-05 09:32:00'
    union all
    select '张三', '2014-08-05 15:15:00'
    union all
    select '张三', '2014-08-01 08:36:00'
    union all
    select '张三', '2014-08-01 18:10:00'
    union all
    select '张三', '2014-08-02 08:32:00'
    union all
    select '张三', '2014-08-02 18:15:00'
    union all
    select '张三', '2014-08-25 08:00:00'
    union all
    select '张三', '2014-08-24 19:00:00'
    union all
    select '张三', '2014-08-27 08:00:00'
    union all
    select '张三', '2014-08-27 17:00:00'
    union all
    select '张三', '2014-08-26 10:00:00'
    union all
    select '张三', '2014-08-26 18:30:00'
    union all
    select '张三', '2014-08-26 8:00:00'
    union all
    select '张三', '2014-08-27 18:56:00'
              
    GO
    

    我的思路是用一张暂时表得到这个月的全部工作日。将该暂时表与用户进行交叉连接。这样每一个用户在这个月的每一个工作日都有一条记录。

    如果早上9点为上班时间,18点为下班时间,这个能够兴许做成变量的形式。

    declare @time_start datetime
    declare	@time_end datetime 
    
    set @time_start = '2014-08-01 00:00:00'
    set @time_end = DATEADD(M,1,@time_start)
    
    -- 一个月的工作日
    IF object_id('tempdb..#tempDate') is not null
    BEGIN
    	drop table #tempDate
    END
    CREATE table #tempDate
    (	
    	stat_day varchar(10)
    )
    
    IF object_id('tempdb..#tempUserDate') is not null
    BEGIN
    	drop table #tempUserDate
    END
    CREATE table #tempUserDate
    (	
    	
    	stat_day varchar(10),
    	[user_name] varchar(40)
    )
    CREATE clustered index tempUserDate_Index1 on #tempUserDate ([user_name],stat_day)
    
    declare @time_temp datetime
    set @time_temp = @time_start
    while @time_temp < @time_end
    begin
       if datepart(weekday,@time_temp)>1 and datepart(weekday,@time_temp)<7
       begin
    	   insert into #tempDate (stat_day) values (CONVERT(varchar(10),@time_temp,121))
       end
       set @time_temp= dateadd(d,1,@time_temp)
    end
    
    insert into #tempUserDate
    select * from #tempDate  cross join
    (select distinct [user_name] from [kaoqin]) t
    

    从原始的kaoqin表中查询出每一个用户的上班时间和下班时间。假设用户一天的打开记录超过两条。那么就会取最早和最晚的一条分别作为上班时间和下班时间。

    select [user_name],CONVERT(varchar(10),card_time,121) as stat_day,
        MIN(card_time) as on_time,MAX(card_time) as off_time from [kaoqin]
        group by [user_name],CONVERT(varchar(10),card_time,121)

    通过暂时表#tempUserDate和上面的查询结果关联,假设左联接为空,则证明该人员缺勤。

    --缺勤
    select * from #tempUserDate a
    left join
    (
        select [user_name],CONVERT(varchar(10),card_time,121) as stat_day,
        MIN(card_time) as on_time,MAX(card_time) as off_time from [kaoqin]
        group by [user_name],CONVERT(varchar(10),card_time,121)
    ) b on a.[user_name]=b.[user_name] and a.stat_day=b.stat_day
    where [b].[user_name] is null

    以下是迟到和早退的实现SQL。

    --迟到
    select * from #tempUserDate a
    left join
    (
        select [user_name],CONVERT(varchar(10),card_time,121) as stat_day,
        MIN(card_time) as on_time,MAX(card_time) as off_time from [kaoqin]
        group by [user_name],CONVERT(varchar(10),card_time,121)
    ) b on a.[user_name]=b.[user_name] and a.stat_day=b.stat_day
    where CONVERT(varchar(100), [b].[on_time], 8)>'09:00:00'
    
    --早退
    select * from #tempUserDate a
    left join
    (
        select [user_name],CONVERT(varchar(10),card_time,121) as stat_day,
        MIN(card_time) as on_time,MAX(card_time) as off_time from [kaoqin]
        group by [user_name],CONVERT(varchar(10),card_time,121)
    ) b on a.[user_name]=b.[user_name] and a.stat_day=b.stat_day
    where CONVERT(varchar(100), [b].[off_time], 8)<'18:00:00'

    得到的结果

    假设某个人他今天既迟到又早退在终于的结果中都会体现。能够从2014-08-05这条数据看出。当然,这个考勤系统还不完好,比如没有将节日考虑进来,初步的考虑是採用Job定期存储每年的节日,假设员工请假,也须要纳入到系统的考虑中。


  • 相关阅读:
    HTML+CSS面试题汇总(持续更新)
    vue-router
    MongoDB
    闭包
    JavaScript的严格模式
    IO题目
    Java 题目集 编程
    Java题目集 函数
    2.面向对象基础-04继承
    2.面向对象基础-03Java数组
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7224157.html
Copyright © 2020-2023  润新知