`

一个关于考勤统计的sql研究

sql 
阅读更多
     在这里,我们要做一个简单的员工考勤记录查询系统的后台数据库。业务需求如下所示:
     1.统计每天来的最早、来的最晚、走的最早、走得最晚的人的姓名
          1.1 统计每天来得最早的人的姓名和打卡时间
            步骤1:从考勤信息表中查询出每天来得最早的人的上班打卡时间和人员编号
     解决这个问题的时候本来考虑的是在考勤信息记录表中按照日期对考勤信息进行分组,然后取每组中上班时间(att_work_datatime)的最小值,但是后来几经折腾发现group by只能实现分组,而order by只能实现组外排序,因此这个方法只能放弃。再三考虑了一下,可以在分组之前先对表中att_work_datatime列中的所有值进行升序排序后生成一个临时表,然后对这个临时表中的att_work_datatime按照日期再分组,这样对att_work_datatime列按照日期group by之后取的就是每天上班打卡最早的人,我们从attendance_info_table(考勤信息表)表中查询出出每天上班时间最早的人的编号、上班时间和下班时间,sql语句如下: 
         select tmp.att_work_datatime,tmp.after_work_datatime,tmp.emp_id 
          from
          (select id,att_work_datatime,after_work_datatime,emp_id
                from attendance_info_table
                order by att_work_datatime) as tmp
           group by Date(att_work_datatime)
          执行查询结果如下:
          
          结果并不如愿,发现多了一行null值,才发现分组的时候mysql默认将null分为一组,这样就多了一组null数据。这样我们只需要在排序之前过滤掉  打卡时间为null的数据行,sql语句如下:
           select tmp.att_work_datatime,tmp.after_work_datatime,tmp.emp_id
            from
           (select id,att_work_datatime,after_work_datatime,emp_id
                from attendance_info_table
                 where att_work_datatime is not null
order by att_work_datatime) as tmp
     group by Date(att_work_datatime)
     查询出来的结果如下图所示:
     
     步骤2:从员工表和考勤信息表中联结查询出每天来得最早的人的姓名上班打卡时间    
      这样,还没有满足需求,我们要打印的是每天来得最早的人的姓名和上班打卡时间,由于员工的信息在另外一张表employee_info_table中放着,这样我们需要用到多表联结查询,根据雇员编号进行等值联结查询,sql语句如下所示:
     select em.emp_name,tmp.att_work_datatime
     from employee_info_table as em ,
     (select id,att_work_datatime,after_work_datatime,emp_id
          from attendance_info_table
          where att_work_datatime is not null
          order by att_work_datatime )
     as tmp
     where em.id=tmp.emp_id
     group by Date(att_work_datatime)
 
select eit.*, ait.att_work_datatime
from attendance_info_table ait, employee_info_table eit
where ait.emp_id = eit.id and ait.att_work_datatime in
     (select min(att_work_datatime)
       from attendance_info_table
        where att_work_datatime is not null
          group by Date(att_work_datatime))
order by ait.att_work_datatime asc;
     查询出来的结果如下图所示:
     
     OK,大功告成。在这里要说明的是,为了缩短sql语句并且为了在一条sql语句中多次使用相同的表,上面的查询中我们使用em 作为员工信息表employee_info_table 的表别名,使用tmp作为排序后生成的临时表的表别名。
     1.2 统计每天来得最晚的人的姓名和打卡时间
     步骤和2.1中统计每天来的最早的人的方法相同,唯一不同的是分组之前先对表中att_work_datatime列中的所有值进行降序排序,sql语句如下:
     select em.emp_name,tmp.att_work_datatime 
     from employee_info_table as em ,
     (select id,att_work_datatime,after_work_datatime,emp_id
          from attendance_info_table
          where att_work_datatime is not null
          order by att_work_datatime desc)
     as tmp
     where em.id=tmp.emp_id
     group by Date(att_work_datatime)
 
select eit.*, ait.att_work_datatime 
from attendance_info_table ait, employee_info_table eit
where ait.emp_id = eit.id and ait.att_work_datatime in
     (select max(att_work_datatime) 
     from attendance_info_table 
     where att_work_datatime is not null 
     group by Date(att_work_datatime))
order by ait.att_work_datatime asc;
     执行查询的结果如下:
     
 
      1.3 统计每天走得最早的人的姓名和打卡时间
             步骤和2.1中统计每天来的最早的人的方法相同,唯一不同的是对表中列中after_work_datatime的所有值进行升   序排序,并将查询的列由att_work_datatime改为after_work_datatime,sql语句如下:
          select em.emp_name,tmp.after_work_datatime 
          from employee_info_table as em ,
          (select id,att_work_datatime,after_work_datatime,emp_id
               from attendance_info_table
               where after_work_datatime is not null
               order by after_work_datatime)
          as tmp
          where em.id=tmp.emp_id
          group by Date(after_work_datatime)
 
select eit.*, ait.after_work_datatime 
from attendance_info_table ait, employee_info_table eit
where ait.emp_id = eit.id and ait.after_work_datatime in 
     (select min(after_work_datatime)
     from attendance_info_table
     where after_work_datatime is not null
     group by Date(after_work_datatime))
order by ait.after_work_datatime asc;
     查询结果如下:
          
 
      1.4 统计每天走得最晚的人的姓名和打卡时间
           步骤和2.2中统计每天来的最晚的人的方法相同,唯一不同的是对表中列中after_work_datatime的所有值进行降序排序,并将查询的列由att_work_datatime改为after_work_datatime,sql语句如下:
     select em.emp_name,tmp.after_work_datatime 
     from employee_info_table as em ,
     (select id,att_work_datatime,after_work_datatime,emp_id
          from attendance_info_table
          where after_work_datatime is not null
          order by after_work_datatime desc)
     as tmp
     where em.id=tmp.emp_id
     group by Date(after_work_datatime)
 
select eit.*, ait.after_work_datatime
from attendance_info_table ait, employee_info_table eit
where ait.emp_id = eit.id and ait.after_work_datatime in
     (select max(after_work_datatime)
     from attendance_info_table
     where after_work_datatime is not null
     group by Date(after_work_datatime))
order by ait.after_work_datatime asc;
     查询结果如下:
     
  
    2.统计每天工作时间最长、工作时间最短的人的姓名
      2.1统计每天工作时间最长的人的姓名
          步骤1:从考勤信息表中查询出每天工作时间最长的人的编号和工作时长
          解决这个问题,我们需要建立在问题1解决方法的基础上,我们先取出考勤信息表中上班打卡时间att_work_datatime、下班打卡时          间after_work_datatime、上下班打卡时间之差作为一天的工作时长att_time以及员工编号emp_id生成一个临时表tmp并将打卡时间为null的数据过滤掉,然后对tmp表中的att_time进行降序排 序然后根据日期进行分组,这样我们就可以从attendance_info_table(考勤信息表)表中查询出每天工作时间最长的人的编号和此人的工作时长。为了计算两个时间差,我们使用mysql自带的函数timediff(time1,time2)来计算time1-time2的时长。sql语句如下:
               select tmp.att_time,tmp.emp_id
               from
               (select id,att_work_datatime,after_work_datatime,timediff(after_work_datatime,att_work_datatime) as att_time,emp_id
                    from attendance_info_table
                    where att_work_datatime is not null and after_work_datatime is not null
                   order by att_time desc) as tmp
                 group by Date(att_work_datatime)
                  查询出的结果如下图所示:
                   
               步骤2:从考勤信息表和员工表中利用等值联结查询出每天工作时间最长的人的姓名和工作时长
               我们根据雇员编号进行等值联结查询出每天工作时间最长的人的姓名和工作时长,sql语句如下所示:
select eit.*,tmp.att_time, tmp.att_work_datatime
from employee_info_table eit,
     (select id,att_work_datatime,timediff(after_work_datatime,att_work_datatime) as att_time,emp_id
     from attendance_info_table
     where att_work_datatime is not null and after_work_datatime is not null) as tmp
where eit.id=tmp.emp_id and tmp.att_time in
(select max(timediff(after_work_datatime,att_work_datatime)) as att_time   
        from attendance_info_table
        where att_work_datatime is not null and after_work_datatime is not null
     group by date(att_work_datatime))
group by date(tmp.att_work_datatime)
order by att_work_datatime;
执行出的结果如下图所示:
            
      2.2统计每天工作时间最短的人的姓名
select eit.*,tmp.att_time, tmp.att_work_datatime
from employee_info_table eit,
     (select id,att_work_datatime,timediff(after_work_datatime,att_work_datatime) as att_time,emp_id
     from attendance_info_table
     where att_work_datatime is not null and after_work_datatime is not null) as tmp
where eit.id=tmp.emp_id and tmp.att_time in
(select min(timediff(after_work_datatime,att_work_datatime)) as att_time    
        from attendance_info_table
        where att_work_datatime is not null and after_work_datatime is not null
     group by date(att_work_datatime))
group by date(tmp.att_work_datatime)
order by att_work_datatime;
          执行结果如下所示:
          
     3.统计每天迟到的人数、早退的人数
     3.1统计每天迟到的人数
select date(att_work_datatime) as date,count(*)  as late_nums
from attendance_info_table
where timediff(time(att_work_datatime),'09:30:59') > 0 and att_work_datatime is not null
group by date(att_work_datatime)
     执行结果如下图所示:
     
      3.2统计每天早退的人数
select date(after_work_datatime) as date,count(*)  as leave_early_nums
from attendance_info_table
where after_work_datatime is not null
     and timediff(time(after_work_datatime),'18:00:00')<0
     or timediff(after_work_datatime,att_work_datatime)<'08:00:00'
group by date(after_work_datatime)      
执行结果如下图所示:
     
     4.统计每个月迟到的人按迟到次数降序排序
select eit.*, count(*) as late_nums
from attendance_info_table as ait,employee_info_table as eit
where ait.att_work_datatime is not null
     and timediff(time(ait.att_work_datatime),'09:30:59') > 0
     and ait.emp_id = eit.id   
group by emp_id
order by  late_nums desc;
          执行结果如下:
     
     5.统计出迟到的人并按姓名按升序排序,打印出迟到的时间
select eit.*,timediff(time(ait.att_work_datatime),'09:30:59') as lately_times,date(ait.att_work_datatime) as lately_date
from attendance_info_table as ait,employee_info_table as eit
where ait.att_work_datatime is not null
     and timediff(time(ait.att_work_datatime),'09:30:59') > 0
     and eit.id=ait.emp_id
order by eit.emp_name asc;
执行结果如下:
     6.公司规定:每迟到一次扣10块钱,每分钟扣1块钱,计算出每天迟到的人扣的钱和公司一天因为迟到扣的钱的总数
     6.1计算出每天迟到的人扣的钱
select eit.*,timediff(time(ait.att_work_datatime),'09:30:59') as lately_times,date(ait.att_work_datatime) as lately_date,(10+1*(TIME_TO_SEC(timediff(time(ait.att_work_datatime),'09:30:59')))/60) as '罚金(元)'
from attendance_info_table as ait,employee_info_table as eit
where ait.att_work_datatime is not null
     and timediff(time(ait.att_work_datatime),'09:30:59') > 0
     and eit.id=ait.emp_id
order by eit.emp_name asc
执行结果如下:
6.1计算出公司每天因为迟到所扣的钱
select tmp.lately_date,sum(tmp.fadefor)  as '总罚金(元)'
from
     (select eit.*,timediff(time(ait.att_work_datatime),'09:30:59') as lately_times,date(ait.att_work_datatime) as lately_date,(10+1*(TIME_TO_SEC(timediff(time(ait.att_work_datatime),'09:30:59')))/60) as fadefor
     from attendance_info_table as ait,employee_info_table as eit
     where ait.att_work_datatime is not null
          and timediff(time(ait.att_work_datatime),'09:30:59') > 0
          and eit.id=ait.emp_id
     order by eit.emp_name asc) as tmp
group by  tmp.lately_date
执行结果如下:
     7.统计出每个月每个人因为迟到扣多少钱,按扣的钱数降序排序列出名单
     步骤一:统计出每个人每天迟到的时间并计算每个人每天的罚金
               方法同6.1
        步骤二:根据人员编号进行分组,统计每个人每个月所扣的钱,并排序
select tmp.id,tmp.emp_name,sum(tmp.fadefor) as 'total_fadefor' from
     (select eit.*,(10+1*(TIME_TO_SEC(timediff(time(ait.att_work_datatime),'09:30:59')))/60) as 'fadefor'
     from attendance_info_table as ait,employee_info_table as eit
     where ait.att_work_datatime is not null
          and timediff(time(ait.att_work_datatime),'09:30:59') > 0
          and eit.id=ait.emp_id) as tmp
group by tmp.id
order by total_fadefor desc;    
          
           查询结果如下:
          
   8.列举出既没有迟到也没有早退记录的人的名单
     步骤一:统计出每个人每个月正常出勤的天数
select eit.*,count(*) as normal_nums
from attendance_info_table as ait,employee_info_table as eit
where ait.att_work_datatime is not null
     and ait.after_work_datatime is not null
     and timediff(time(ait.att_work_datatime),'09:30:59') < 0
     and timediff(after_work_datatime,att_work_datatime)>'08:00:00'
     and ait.emp_id = eit.id    
group by ait.emp_id
 
步骤2:查询出出勤次数大于指定天数的人的名单
select tmp.id,tmp.emp_name from
(select eit.*,count(*) as normal_nums
from attendance_info_table as ait,employee_info_table as eit
where ait.att_work_datatime is not null
     and ait.after_work_datatime is not null
     and timediff(time(ait.att_work_datatime),'09:30:59') < 0
     and timediff(after_work_datatime,att_work_datatime)>'08:00:00'
     and ait.emp_id = eit.id
group by ait.emp_id
)as tmp where tmp.normal_nums>=21 
步骤三:通过获取一个月的天数,查询出一个月每天都正常出勤的人的名单
select tmp.id,tmp.emp_name from
(select eit.*,count(*) as normal_nums
from attendance_info_table as ait,employee_info_table as eit
where ait.att_work_datatime is not null
     and ait.after_work_datatime is not null
     and timediff(time(ait.att_work_datatime),'09:30:59') < 0
     and timediff(after_work_datatime,att_work_datatime)>'08:00:00'
     and ait.emp_id = eit.id
group by ait.emp_id
)as tmp
where tmp.normal_nums>=
(select count(*)
     from
     (select date(att_work_datatime)  as date
     from attendance_info_table
     where att_work_datatime is not null
     group by date(att_work_datatime)) as tmp)
执行结果如下:
1
0
分享到:
评论
2 楼 asialee 2014-04-11  
shinyatime 写道
怎么图片显示不出来啊

我这边可以呀,是不是网速的问题,这个是从evernote里面直接复制过来的。
1 楼 shinyatime 2014-04-11  
怎么图片显示不出来啊

相关推荐

    PHP+SQL考勤系统安全性实现源码 - 保护企业考勤数据安全

    系统功能包括员工考勤记录、请假管理、加班统计、报表生成等。特别强调安全性,采用加密技术和多重身份验证机制,保护数据不被未授权访问。用户界面友好,操作简便,后台管理高效。源码提供完整的功能实现,便于学习...

    毕设源码-vb+sql职工考勤管理系统职工考勤管理系统(论文+系统+开题报告).rar

    职工考勤管理系统是一个基于VB和SQL的实用工具,旨在帮助企业和组织高效管理员工考勤。该系统集成了先进的数据库技术和用户友好的界面设计,确保数据的准确性和操作的便捷性。 主要功能包括: 1. 灵活的考勤规则...

    PHP+SQL考勤系统安全性实现(毕业设计).zip

    在需求分析这个阶段,需要仔细的研究系统所实现的功能,并进一步将他们具体化。 1.任务概述 目标 将学生考勤、平时成绩的评定、以及成绩查询的大量业务,用计算机系统操作完成,对它进行全面现代化管理,以便提高...

    PHP+SQL考勤系统安全性实现(源代码+论文+答辩PPT+指导书).zip

    在需求分析这个阶段,需要仔细的研究系统所实现的功能,并进一步将他们具体化。 1.任务概述  目标 将学生考勤、平时成绩的评定、以及成绩查询的大量业务,用计算机系统操作完成,对它进行全面现代化管理,以便提高...

    Java毕业设计-JAVA+SQL办公自动化系统(源代码+论文+外文翻译).rar

    本资源提供了一个全面的JAVA+SQL办公自动化系统的源代码、论文及外文翻译。该系统旨在通过使用Java编程语言和SQL数据库技术,实现企业或组织内部的日常办公流程的自动化管理。 **核心功能**: 1. 用户管理:支持...

    考勤系统数据库课程设计.doc

    一个界面友好,易于操 作的员工考勤管理软件进行自动化处理就会显得尤为重要。 在数据库系统中,主要的操作是对数据库进行的,根据对不同数据表的操作来划分模 块,虽然这并不一定正确,但根据数据来划分模块确实...

    人力资源管理系统

    每个rar为一个子系统/此程序只供学习研究,不得用于商业行为,违者后果自付 说明:该部分程序为公司人力资源产品的所有资源 目录说明: public : 程序公共资源及文 报表 : 人力资源报表设计器 工资管理:...

    基于Web的学生上机实验管理系统的设计与实现

    实现了上机教学任务的安排与维护、上机自动考勤、作业上传、作业成绩登记和作业成绩的综合统计、信息的导入、导出等智能化管理,系统采用B/S模式,以J2EE+SQL Server2008为开发平台,较好的利用了数据库技术、构件技术...

    OA系统+手机版源码t源代码

    利用最新的ASP.NET平台、javascript和AJAX、SQLSERVER关系型数据库等技术,结合OA思想的独特设计,建立一个开放的信息资源管理平台。 利用数据库及分布式处理技术、模块化功能设计,构造信息存储与事务处理平台。该...

    基于Web的学生上机实验管理系统的设计与实现 (2014年)

    实现了上机教学任务的安排与维护、上机自动考勤、作业上传、作业成绩登记和作业成绩的综合统计、信息的导入、导出等智能化管理,系统采用B/S模式,以J2EE + SQL Server2008为开发平台,较好的利用了数据库技术、构件...

    log4Net详解(共2讲)

    国讯OA的一个强大之处就是在于它可以让系统在运作的过程中自动触发请求,并且还可以根据前一个请求的实际状况对下一个触发的请求进行智能选择。 6、分支选择流 根据上一步的选择,选择不同的分支进行流程执行。如...

Global site tag (gtag.js) - Google Analytics