处理考勤打卡记录问题

Andy-W 2007-06-12 11:00:55
--打卡记录表
CREATE TABLE OriginalData([id] int IDENTITY(1,1),EmployeeID int,CheckTime datetime)
INSERT INTO OriginalData
SELECT 1,'2007-06-11 08:01' UNION ALL
SELECT 1,'2007-06-11 12:02' UNION ALL
SELECT 1,'2007-06-11 13:05' UNION ALL
SELECT 1,'2007-06-11 17:40' UNION ALL
SELECT 1,'2007-06-11 19:00' UNION ALL
SELECT 1,'2007-06-11 23:42' UNION ALL
SELECT 1,'2007-06-11 23:58' UNION ALL
SELECT 1,'2007-06-12 07:50' UNION ALL
SELECT 1,'2007-06-12 12:00' UNION ALL
SELECT 3,'2007-06-11 20:00' UNION ALL
SELECT 3,'2007-06-12 04:00' UNION ALL
SELECT 3,'2007-06-12 07:55' UNION ALL
SELECT 3,'2007-06-12 12:00' UNION ALL
SELECT 3,'2007-06-12 13:00' UNION ALL
SELECT 3,'2007-06-12 17:35'
--考勤表
CREATE TABLE OnOffDutyData(EmployeeID int,CheckDate datetime
,OnDuty1 datetime,OffDuty1 datetime
,OnDuty2 datetime,OffDuty2 datetime
,OnDuty3 datetime,OffDuty3 datetime
,OnDuty4 datetime,OffDuty4 datetime)
INSERT INTO OnOffDutyData (EmployeeID,CheckDate)
SELECT 1,'2007-06-11' UNION ALL
SELECT 1,'2007-06-12' UNION ALL
SELECT 3,'2007-06-11' UNION ALL
SELECT 3,'2007-06-12'

SELECT * FROM OriginalData
SELECT * FROM OnOffDutyData
/*
想要的初始化结果:
EmployeeID CheckDate OnDuty1 OffDuty1 OnDuty2 OffDuty2 OnDuty3 OffDuty3 OnDuty4
1 2007-06-11 08:01 12:02 13:05 17:40 19:00 23:42 07:50 --(07:50为第2天的第一次打卡记录)
1 2007-06-12 07:50 12:00 NULL NULL NULL NULL NULL
3 2007-06-11 20:00 04:00 (04:00 为第2天第1次打卡,其他段为如上行为NULL)
4 2007-06-12 04:00 07:55 12:00 13:00 17:35 NULL NULL

--方法说明:
按EmployeeID 和 打卡日期 CONVERT(nchar(10),CheckTime,120) ,每天提取当天前6次打卡记录和第2天第一次打卡记录
UPDATE 考勤表(OnOffDutyData)。

打卡记录表数据大小: 5000(人)×30(天)×6(大约每天的打卡次数)=90万条记录
考勤表数据大小: 5000(人)×30(天)=15万条记录

要求一个能提高效率的Update方法,具体实现方法不限。
*/

DROP TABLE OriginalData,OnOffDutyData

--分数不够到时候再补,先放100分!
...全文
1751 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
shuijing_love 2007-06-14
  • 打赏
  • 举报
回复
收藏~!
lao_bulls 2007-06-14
  • 打赏
  • 举报
回复
收藏
friendjin 2007-06-13
  • 打赏
  • 举报
回复
1.truncate table
2.修改考勤表,增加刷卡记录标记
3按标记依次更新update
以上意见仅供参考
friendjin 2007-06-13
  • 打赏
  • 举报
回复
其实提高性能原理很简单:
  1.不要使用游标
  2.消除排序
只要满足这两个条件肯定是没有问题的
Andy-W 2007-06-13
  • 打赏
  • 举报
回复
解决方法已经找到。谢谢各位的热心帮助,不知如何报答,只有放分!
Andy-W 2007-06-12
  • 打赏
  • 举报
回复
to:
leo_lesley(leo) ( )

方法不错。我先测试,看看。

希望还有更好的方法。

再加100分
budong0000 2007-06-12
  • 打赏
  • 举报
回复
结合下job,view做做。。
leo_lesley 2007-06-12
  • 打赏
  • 举报
回复
--打卡记录表
CREATE TABLE OriginalData([id] int IDENTITY(1,1),EmployeeID int,CheckTime datetime)
INSERT INTO OriginalData
SELECT 1,'2007-06-11 08:01' UNION ALL
SELECT 1,'2007-06-11 12:02' UNION ALL
SELECT 1,'2007-06-11 13:05' UNION ALL
SELECT 1,'2007-06-11 17:40' UNION ALL
SELECT 1,'2007-06-11 19:00' UNION ALL
SELECT 1,'2007-06-11 23:42' UNION ALL
SELECT 1,'2007-06-11 23:58' UNION ALL
SELECT 1,'2007-06-12 07:50' UNION ALL
SELECT 1,'2007-06-12 12:00' UNION ALL
SELECT 3,'2007-06-11 20:00' UNION ALL
SELECT 3,'2007-06-12 04:00' UNION ALL
SELECT 3,'2007-06-12 07:55' UNION ALL
SELECT 3,'2007-06-12 12:00' UNION ALL
SELECT 3,'2007-06-12 13:00' UNION ALL
SELECT 3,'2007-06-12 17:35'
--考勤表
CREATE TABLE OnOffDutyData(EmployeeID int,CheckDate datetime
,OnDuty1 datetime,OffDuty1 datetime
,OnDuty2 datetime,OffDuty2 datetime
,OnDuty3 datetime,OffDuty3 datetime
,OnDuty4 datetime,OffDuty4 datetime)
INSERT INTO OnOffDutyData (EmployeeID,CheckDate)
SELECT 1,'2007-06-11' UNION ALL
SELECT 1,'2007-06-12' UNION ALL
SELECT 3,'2007-06-11' UNION ALL
SELECT 3,'2007-06-12'


declare @t table(EmployeeID int,CheckDate datetime,OnDuty1 varchar(10),OnDuty2 varchar(10),OnDuty3 varchar(10),OnDuty4 varchar(10),OnDuty5 varchar(10),OnDuty6 varchar(10),OnDuty7 varchar(10),OnDuty8 varchar(10))
declare @lsb table(EmployeeID int,d datetime,m varchar(10),cnt int)

insert @lsb
SELECT b.EmployeeID,d=convert(char(10),b.CheckTime,21),m=right(convert(char(16),b.CheckTime,21),5),
Cnt=(select count(1) from OriginalData where EmployeeID=b.EmployeeID and convert(char(10),b.CheckTime,21)=convert(char(10),CheckTime,21) and CheckTime<b.CheckTime )
FROM OriginalData b

insert @t
SELECT a.EmployeeID,CheckDate=convert(char(10),a.CheckDate,21),
OnDuty1=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 0 then m else null end),
OnDuty1=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 1 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end)),
OnDuty2=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 2 then m else null end),
OnDuty2=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 3 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end)),
OnDuty3=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 4 then m else null end),
OnDuty3=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 5 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end)),
OnDuty4=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 6 then m else null end),
OnDuty4=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 7 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end))
FROM OnOffDutyData a left join @lsb b on a.EmployeeID=b.EmployeeID
group by a.EmployeeID,CheckDate
order by a.EmployeeID,CheckDate

delete from OnOffDutyData

insert OnOffDutyData
select EmployeeID,CheckDate,
CheckDate+OnDuty1,OnDuty2=case when OnDuty1 is not null then CheckDate+OnDuty2 else null end,
CheckDate+OnDuty3,OnDuty4=case when OnDuty3 is not null then CheckDate+OnDuty4 else null end,
CheckDate+OnDuty5,OnDuty6=case when OnDuty5 is not null then CheckDate+OnDuty6 else null end,
CheckDate+OnDuty7,OnDuty8=case when OnDuty7 is not null then CheckDate+OnDuty8 else null end
from @t



select * from OnOffDutyData
leo_lesley 2007-06-12
  • 打赏
  • 举报
回复
--打卡记录表
CREATE TABLE OriginalData([id] int IDENTITY(1,1),EmployeeID int,CheckTime datetime)
INSERT INTO OriginalData
SELECT 1,'2007-06-11 08:01' UNION ALL
SELECT 1,'2007-06-11 12:02' UNION ALL
SELECT 1,'2007-06-11 13:05' UNION ALL
SELECT 1,'2007-06-11 17:40' UNION ALL
SELECT 1,'2007-06-11 19:00' UNION ALL
SELECT 1,'2007-06-11 23:42' UNION ALL
SELECT 1,'2007-06-11 23:58' UNION ALL
SELECT 1,'2007-06-12 07:50' UNION ALL
SELECT 1,'2007-06-12 12:00' UNION ALL
SELECT 3,'2007-06-11 20:00' UNION ALL
SELECT 3,'2007-06-12 04:00' UNION ALL
SELECT 3,'2007-06-12 07:55' UNION ALL
SELECT 3,'2007-06-12 12:00' UNION ALL
SELECT 3,'2007-06-12 13:00' UNION ALL
SELECT 3,'2007-06-12 17:35'
--考勤表
CREATE TABLE OnOffDutyData(EmployeeID int,CheckDate datetime
,OnDuty1 datetime,OffDuty1 datetime
,OnDuty2 datetime,OffDuty2 datetime
,OnDuty3 datetime,OffDuty3 datetime
,OnDuty4 datetime,OffDuty4 datetime)
INSERT INTO OnOffDutyData (EmployeeID,CheckDate)
SELECT 1,'2007-06-11' UNION ALL
SELECT 1,'2007-06-12' UNION ALL
SELECT 3,'2007-06-11' UNION ALL
SELECT 3,'2007-06-12'



declare @t table(EmployeeID int,CheckDate datetime,OnDuty1 varchar(10),OnDuty2 varchar(10),OnDuty3 varchar(10),OnDuty4 varchar(10),OnDuty5 varchar(10),OnDuty6 varchar(10),OnDuty7 varchar(10),OnDuty8 varchar(10))
declare @lsb table(EmployeeID int,d datetime,m varchar(10),cnt int)

insert @lsb
SELECT b.EmployeeID,d=convert(char(10),b.CheckTime,21),m=right(convert(char(16),b.CheckTime,21),5),
Cnt=(select count(1) from OriginalData where EmployeeID=b.EmployeeID and convert(char(10),b.CheckTime,21)=convert(char(10),CheckTime,21) and CheckTime<b.CheckTime )
FROM OriginalData b

insert @t
SELECT a.EmployeeID,CheckDate=convert(char(10),a.CheckDate,21),
OnDuty1=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 0 then m else null end),
OnDuty1=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 1 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end)),
OnDuty2=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 2 then m else null end),
OnDuty2=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 3 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end)),
OnDuty3=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 4 then m else null end),
OnDuty3=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 5 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end)),
OnDuty4=max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 6 then m else null end),
OnDuty4=isnull(max(case when a.EmployeeID=b.EmployeeID and convert(char(10),a.CheckDate,21)=d and cnt = 7 then m end),min(case when a.EmployeeID=b.EmployeeID and cnt = 0 and convert(char(10),a.CheckDate,21)<d then m end))
FROM OnOffDutyData a left join @lsb b on a.EmployeeID=b.EmployeeID
group by a.EmployeeID,CheckDate
order by a.EmployeeID,CheckDate

select EmployeeID,CheckDate,
OnDuty1,OnDuty2=case when OnDuty1 is not null then OnDuty2 else null end,
OnDuty3,OnDuty4=case when OnDuty3 is not null then OnDuty4 else null end,
OnDuty5,OnDuty6=case when OnDuty5 is not null then OnDuty6 else null end,
OnDuty7,OnDuty8=case when OnDuty7 is not null then OnDuty8 else null end
from @t
Yang_ 2007-06-12
  • 打赏
  • 举报
回复
测试下以下笨方法的速度如何(特别注意:我直接删除了OriginalData标的数据,如果这时你的原始表,需要保存数据的,请用个临时表,并倒入OriginalData标的所有数据)



update a
set OnDuty1=(select top 1 checktime from OriginalData where EmployeeID=a.EmployeeID and CheckTime>=a.CheckDate and CheckTime<dateadd(day,1,a.CheckDate)),
OnDuty4=(select top 1 checktime from OriginalData where EmployeeID=a.EmployeeID and CheckTime>=dateadd(day,1,a.CheckDate) and CheckTime<dateadd(day,2,a.CheckDate))
from OnOffDutyData a

delete a
from OriginalData a
where not exists (
select 1 from OriginalData
where EmployeeID=a.EmployeeID and
convert(Nchar(10),CheckTime,120)=convert(Nchar(10),a.CheckTime,120)
and CheckTime<a.CheckTime
)

update a
set OffDuty1=(select top 1 checktime from OriginalData where EmployeeID=a.EmployeeID and CheckTime>=a.CheckDate and CheckTime<dateadd(day,1,a.CheckDate))
from OnOffDutyData a

delete a
from OriginalData a
where not exists (
select 1 from OriginalData
where EmployeeID=a.EmployeeID and
convert(Nchar(10),CheckTime,120)=convert(Nchar(10),a.CheckTime,120)
and CheckTime<a.CheckTime
)

update a
set OnDuty2=(select top 1 checktime from OriginalData where EmployeeID=a.EmployeeID and CheckTime>=a.CheckDate and CheckTime<dateadd(day,1,a.CheckDate))
from OnOffDutyData a

delete a
from OriginalData a
where not exists (
select 1 from OriginalData
where EmployeeID=a.EmployeeID and
convert(Nchar(10),CheckTime,120)=convert(Nchar(10),a.CheckTime,120)
and CheckTime<a.CheckTime
)

update a
set OffDuty2=(select top 1 checktime from OriginalData where EmployeeID=a.EmployeeID and CheckTime>=a.CheckDate and CheckTime<dateadd(day,1,a.CheckDate))
from OnOffDutyData a

delete a
from OriginalData a
where not exists (
select 1 from OriginalData
where EmployeeID=a.EmployeeID and
convert(Nchar(10),CheckTime,120)=convert(Nchar(10),a.CheckTime,120)
and CheckTime<a.CheckTime
)

update a
set OnDuty3=(select top 1 checktime from OriginalData where EmployeeID=a.EmployeeID and CheckTime>=a.CheckDate and CheckTime<dateadd(day,1,a.CheckDate))
from OnOffDutyData a

delete a
from OriginalData a
where not exists (
select 1 from OriginalData
where EmployeeID=a.EmployeeID and
convert(Nchar(10),CheckTime,120)=convert(Nchar(10),a.CheckTime,120)
and CheckTime<a.CheckTime
)

update a
set OffDuty3=(select top 1 checktime from OriginalData where EmployeeID=a.EmployeeID and CheckTime>=a.CheckDate and CheckTime<dateadd(day,1,a.CheckDate))
from OnOffDutyData a

delete a
from OriginalData a
where not exists (
select 1 from OriginalData
where EmployeeID=a.EmployeeID and
convert(Nchar(10),CheckTime,120)=convert(Nchar(10),a.CheckTime,120)
and CheckTime<a.CheckTime
)
Andy-W 2007-06-12
  • 打赏
  • 举报
回复
to Yang_(扬帆破浪):
INSERT INTO 不是重要,主要是处理打卡数据,怎么样提高运行效率。
找不到一个好的方法。
hellowork 2007-06-12
  • 打赏
  • 举报
回复
结果:
EmployeeID CheckTime OnDuty1 OnOffDuty1 OnDuty2 OnOffDuty2 OnDuty3 OnOffDuty3 OnDuty4
----------- ---------- ------- ---------- ------- ---------- ------- ---------- -------
1 2007-06-11 08:01 12:02 13:05 17:40 19:00 23:42 07:50
1 2007-06-12 07:50 12:00 NULL NULL NULL NULL NULL
3 2007-06-11 20:00 04:00 NULL NULL NULL NULL NULL
3 2007-06-12 04:00 07:55 12:00 13:00 17:35 NULL NULL
Andy-W 2007-06-12
  • 打赏
  • 举报
回复
4:00是凌晨打的卡,7:50的早上打的卡。很多工厂为了加班经常出现这样的差不多24小时上班情况。

目前我使用游标计算方法只能按天处理,不能多天,因为游标太慢,没办法。

先谢谢Yang_(扬帆破浪)的关注。
Yang_ 2007-06-12
  • 打赏
  • 举报
回复
可能用update的速度不如用insert,就是先清空OnOffDutyData表(最好本来就空的)
hellowork 2007-06-12
  • 打赏
  • 举报
回复
OnDuty4=(select top 1 convert(varchar(5),CheckTime,108) from @OriginalData as a where EmployeeID = t.EmployeeID and datediff(dd,t.CheckTime,CheckTime)=1 order by CheckTime)
from @OriginalData as t ) AS x
GROUP BY EmployeeID,CheckTime ORDER BY 1,2
--请楼主把上面三段SQL连起来.我这里无法把完整的帖出来(无法发送),只好拆开,不知道CSDN又怎么了.
hellowork 2007-06-12
  • 打赏
  • 举报
回复
OnOffDuty2=(select convert(varchar(5),CheckTime,108) from @OriginalData as a where EmployeeID = t.EmployeeID and datediff(dd,CheckTime,t.CheckTime) = 0 and
(select count(*) from @OriginalData where EmployeeID = a.EmployeeID and datediff(dd,CheckTime,a.CheckTime) = 0 and CheckTime <= a.CheckTime)= 4),
OnDuty3=(select convert(varchar(5),CheckTime,108) from @OriginalData as a where EmployeeID = t.EmployeeID and datediff(dd,CheckTime,t.CheckTime) = 0 and
(select count(*) from @OriginalData where EmployeeID = a.EmployeeID and datediff(dd,CheckTime,a.CheckTime) = 0 and CheckTime <= a.CheckTime)= 5),
OnOffDuty3=(select convert(varchar(5),CheckTime,108) from @OriginalData as a where EmployeeID = t.EmployeeID and datediff(dd,CheckTime,t.CheckTime) = 0 and
(select count(*) from @OriginalData where EmployeeID = a.EmployeeID and datediff(dd,CheckTime,a.CheckTime) = 0 and CheckTime <= a.CheckTime)= 6),
Yang_ 2007-06-12
  • 打赏
  • 举报
回复
哦,看错
Yang_ 2007-06-12
  • 打赏
  • 举报
回复
EmployeeID=1 的 12号7:50记录用了两次
EmployeeID=3 的 12号4:00记录用了一次

为什么?
hellowork 2007-06-12
  • 打赏
  • 举报
回复
(select EmployeeID,CheckTime=convert(varchar(10),CheckTime,120),
OnDuty1=(select top 1 convert(varchar(5),CheckTime,108) from @OriginalData where EmployeeID = t.EmployeeID and datediff(dd,CheckTime,t.CheckTime) = 0 order by CheckTime),
OnOffDuty1=(select convert(varchar(5),CheckTime,108) from @OriginalData as a where EmployeeID = t.EmployeeID and datediff(dd,CheckTime,t.CheckTime) = 0 and
(select count(*) from @OriginalData where EmployeeID = a.EmployeeID and datediff(dd,CheckTime,a.CheckTime) = 0 and CheckTime <= a.CheckTime)= 2),
OnDuty2=(select convert(varchar(5),CheckTime,108) from @OriginalData as a where EmployeeID = t.EmployeeID and datediff(dd,CheckTime,t.CheckTime) = 0 and
(select count(*) from @OriginalData where EmployeeID = a.EmployeeID and datediff(dd,CheckTime,a.CheckTime) = 0 and CheckTime <= a.CheckTime)= 3),
hellowork 2007-06-12
  • 打赏
  • 举报
回复
SELECT EmployeeID,CheckTime,
OnDuty1=max(OnDuty1),
OnOffDuty1=ISNULL(max(OnOffDuty1),max(OnDuty4)),
OnDuty2=case when max(OnOffDuty1) is null then NULL else ISNULL(max(OnDuty2),max(OnDuty4)) end,
OnOffDuty2=case when max(OnDuty2) is null then NULL else ISNULL(max(OnOffDuty2),max(OnDuty4)) end,
OnDuty3=case when max(OnOffDuty2) is null then NULL else ISNULL(max(OnDuty3),max(OnDuty4)) end,
OnOffDuty3=case when max(OnDuty3) is null then NULL else ISNULL(max(OnOffDuty3),max(OnDuty4)) end,
OnDuty4=case when max(OnOffDuty3) is null then NULL else max(OnDuty4) end
FROM
加载更多回复(4)
一、项目简介本课程演示的是一套基于SSM实现的考勤管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。课程包含:1. 项目源码、项目文档、数据库脚本、软件工具等所有资料2. 带你从零开始部署运行本套系统3. 该项目附带的源码资料可作为毕设使用4. 提供技术答疑二、技术实现后台框架:Spring、SpringMVC、MyBatisUI界面:JSP、jQuery 、H-ui数据库:MySQL 三、系统功能该系统共包含两种角色:员工、管理员,主要分为前台和后台两大模块。1.前台模块 前台首页、新闻公告、员工活动、职位招聘、留言板、用户注册、用户登录、个人中心、我的考勤、我的奖惩、我的培训、我的薪资、修改密码等功能。2.后台模块 系统后台登陆、管理员管理、员工信息管理、部门管理、职务管理、考勤类别管理、员工考勤管理、员工奖惩管理、员工培训管理、员工薪资管理、网站栏目管理、网站内容管理、职位招聘管理、求职简历管理、留言交流管理、留言回复管理等功能。该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 四、项目截图1)前台首面2)个人信息页面3)员工信息管理4)考勤类别管理5)考勤信息管理6)员工薪资管理  更多Java毕设项目请关注【毕设系列课程】https://edu.csdn.net/lecturer/2104   

22,209

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧