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

     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. java.io.FileNotFoundException: antlr-2.7.7.jar (系统找不到指定的路径。)[待解决]

    严重: Failed to destroy the filter named [struts2] of type [org.apache.struts2.dispatcher.ng.filter.St ...

  2. uri 定义

    function path(){ $path=explode("/",$_SERVER['REQUEST_URI']); unset($path[(count($path)-1)] ...

  3. 【Cocos2d-X(1.x 2.x) 修复篇】iOS6 中 libcurl.a 无法通过armv7s编译以及iOS6中无法正常游戏横屏的解决方法

    本站文章均为李华明Himi原创,转载务必在明显处注明:转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/iphone-cocos2dx/1000.html ...

  4. ubuntu下的烧录工具

    Flash Image Tool1.0 为了ubuntu下能够方便地烧录版本,我开发了Flash Image Tool.现在服务器(192.167.100.225)上有一份它的拷贝share/Tool ...

  5. Remastersys---制作当前的ubuntu系统镜像iso,自定义ubuntu系统

    Remastersys---制作当前的ubuntu系统镜像iso,自定义ubuntu系统 Remastersys则款软件,我们就是使用他来将当前的系统制作成iso镜像,一方面可以用来备份系统,二来可以 ...

  6. Centos编译Unix网络编程(第三版)卷1的源代码

    测试环境:Centos 1)在shell中输入./configure然后按回车(注意先让configure有执行权限 chomd 777 configure) 2)依次进入lib.libfree.li ...

  7. exit和return

    函数名: exit() 所在头文件:stdlib.h(如果是”VC6.0“的话头文件为:windows.h) 功 能: 关闭所有文件,终止正在执行的进程. exit(1)表示异常退出.这个1是返回给操 ...

  8. test20180830

    所有试题限制均为128MB,1Sec 总分100(•́へ•́╬). 试题一 A题 问题描述: Bob 有 n 个士兵,他们排成一列按照从左到右编号为 1 到 n,每个士兵都有自己的 IQ 值,Bob ...

  9. encode decode enumerate

    format的用法 print(format('aa','>20')) print(format('aa','<20')) print(format('aa','^20')) 打印结果如下 ...

  10. RequireJS 学习

    几个学习点: 配置模块路径 定义模块 配置不支持 AMD jsonp 服务 text 插件 css 插件