php mysql 考勤系统_考勤问题思路和解决

最近在做一个考勤系统,考勤主要关注的是缺勤、迟到和早退,目前的打卡控制器可以记录用户名和打卡时间,用户可能一天打卡多次,也可能一天只打了一次卡,这些情况都需要考虑。打卡信息都存储在考勤表中,从中要挖掘出一个月内的缺勤人员,迟到人员和早退人

最近在做一个考勤系统,考勤主要关注的是缺勤、迟到和早退,目前的打卡控制器可以记录用户名和打卡时间,用户可能一天打卡多次,也可能一天只打了一次卡,这些情况都需要考虑。打卡信息都存储在考勤表中,从中要挖掘出一个月内的缺勤人员,迟到人员和早退人员,并且能显示缺勤、迟到和早退的时间。

考勤表

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)

得到的结果

8faaf53cc7f67b323713c7c3f3c7d5f3.png

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

f68f2add0b68e4f9810432fce46917b7.png

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值