在这里,我们要做一个简单的员工考勤记录查询系统的后台数据库。业务需求如下所示:

     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)
执行结果如下:

一个关于考勤统计的sql研究的更多相关文章

  1. mysql统计类似SQL语句查询次数

    mysql统计类似SQL语句查询次数 vc-mysql-sniffer 工具抓取的sql分析. 1.先用shell脚本把所有enter符号替换为null,再根据语句前后的字符分隔语句 grep -Ev ...

  2. 考勤输入导入OA平台与考勤统计报表导出功能源代码

    注:以某某公司为例,每日签到时间为8点整   每日签退时间为17点30分 规则:公司签到签退时间在OA平台中可以视实际情况调整,当天有请假并通过工作流审批通过为有效,当天因公外出并通过工作流审批通过为 ...

  3. c#考勤统计

    现在项目需求,需要从多张表中获取数据,组装到一个实体对象中,并通过计算统计出每个员工的考勤记录.(全凭自己思考做的,不足的地方希望各位大神指正!毕竟自己能力有限,思考不全) 考勤统计列表: 明细列表: ...

  4. 如果一条SQL语句太长,我们可以通过回车键来创建一个新行来编写SQL语句,SQL语句的命令结束符为分号(;)。

    1.如果一条SQL语句太长,我们可以通过回车键来创建一个新行来编写SQL语句,SQL语句的命令结束符为分号(;). 2.select查询的多个字段之间要用逗号“,”分割,如果查询涉及多个表,那多个表之 ...

  5. --投资情况统计详情sql

    --投资情况统计详情sqlselect BidRecord.*, RegInfo.UserName,UserInfo.phone,BorrowInfo.Title,BorrowInfo.BorrowC ...

  6. 写一个程序,统计自己C语言共写了多少行代码,Github基本操作

    前言 在上一篇博客中,本人提到了自己的文件操作可以说是几乎没用过.现在想想,这也算是只在OJ上做题的一个弊端吧.虽然通过OJ做题是一个学习代码好手段,但其他方面也要多多涉猎才好,而不是说OJ用不到文件 ...

  7. 已知一个字符串S 以及长度为n的字符数组a,编写一个函数,统计a中每个字符在字符串中的出现次数

    import java.util.Scanner; /** * @author:(LiberHome) * @date:Created in 2019/3/6 21:04 * @description ...

  8. 如何用java完成一个中文词频统计程序

    要想完成一个中文词频统计功能,首先必须使用一个中文分词器,这里使用的是中科院的.下载地址是http://ictclas.nlpir.org/downloads,由于本人电脑系统是win32位的,因此下 ...

  9. 核心API的使用(给定一个字符串,统计每个字符出现的次数)

    /** * 给定一个字符串,统计每个字符出现的次数. 如:abdaewrwqask435a1aasd */public class ReplaceString { static int length; ...

随机推荐

  1. IoC基础例子

    一个简单的例子: 一般新建一个com.dao包,存放一些dao接口. com.dao.impl里面存放具体的dao com.service存放service接口 com.service.impl具体的 ...

  2. L240

    Giant rocks from space are falling from the sky more than they used to, but don't worry. For the pas ...

  3. REST easy with kbmMW #15 – Handling HTTP POST

    我被问到有关如何通过基于kbmMW智能服务(Smart Service)的REST处理POST的问题. 这篇博客文章解释了典型的POST各种形式的访问,以及如何在kbmMW中处理它们. POST变种W ...

  4. 逆向路由器固件之敏感信息泄露 Part2

    之前的文章中详细介绍了各种解包路由器固件的工具.解包之后就获得了固件中的文件.下一步就是分析文件寻找漏洞了.这次分析的目标是Trendnet路由器,分析的漏洞是一个远程获取路由器权限的漏洞. 初步分析 ...

  5. SWIFT中正则表达式验证邮箱

    在playground内写入以下代码,正则关键字跟其它语言的没什么区别 class Regex { let internalExpression:NSRegularExpression let pat ...

  6. 1.2.1 Elevator

    Elevator Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem De ...

  7. 第十章 企业项目开发--分布式缓存Redis(2)

    注意:本章代码是在上一章的基础上进行添加修改,上一章链接<第九章 企业项目开发--分布式缓存Redis(1)> 上一章说了ShardedJedisPool的创建过程,以及redis五种数据 ...

  8. 20155117王震宇 2016-2017-2 《Java程序设计》第七周学习总结

    教材学习内容总结 时间度量 格林尼治标准时间(GMT):现在GMT已不作为标准时间使用. 世界时(UT):借助观测远方星体跨过子午线而得,受地球自转速度影响. 国际原子时(TAI):铯原子辐射振动幅度 ...

  9. 压力测试命令行工具SuperBenchmarker

    压力测试命令行工具SuperBenchmarker SuperBenchmarker 是ㄧ个开源的类似于Apache ab的压力测试命令行工具.可以在 .NET 4.52+ 或者 .NET Core ...

  10. Windows环境下搭建Nginx和多版本PHP共存

    PHP版本众多,彼此之间兼容性不好,不同程序经常需要的不同版本的PHP版本.这里介绍如何使用NGINX让不同版本的PHP共存. 软件下载地址 与nginx整合的php需要选择Non Thread Sa ...