SQL 考勤打卡问题

本文介绍了如何使用SQL解决员工考勤打卡问题。通过业务场景描述,明确了早、晚打卡的有效时间,并利用数据准备、过程分析展示了如何利用CASE WHEN和窗口函数区分有效打卡、重复打卡及无效打卡。重点讲解了窗口函数的运用。

1: 业务场景

        员工考勤打卡,分早,晚打卡,早上8:00到9:00 为早上打卡时间,这个时间范围内第一次打卡视为有效打卡,本时间段内其它打卡视为重复打卡;

       相同情况,晚上下班打卡时间范围为17:00到18:00,这个时间范围内的第一次打开视为有效打卡,本时间内的其它打卡视为重复打卡;

       其余时间范围内的打卡视为无效打卡

2:数据准备

Create table T_ClockIn (
UserId int,
CheckIn date
);

Insert into T_ClockIn VALUES (1,'2018/12/1 8:25');
Insert into T_ClockIn VALUES (1,'2018/12/1 8:26');
Insert into T_ClockIn VALUES (1,'2018/12/1 17:02');
Insert into T_ClockIn VALUES (1,'2018/12/2 8:27');
Insert into T_ClockIn VALUES (1,'2018/12/2 8:37');
Insert into T_ClockIn VALUES (1,'2018/12/2 17:27');
Insert into T_ClockIn VALUES (1,'2018/12/2 18:27');
Insert into T_ClockIn VALUES (2,'2018/12/1 8:26');
Insert into T_ClockIn VALUES (2,'2018/12/1 17:03');
Insert into T_ClockIn VALUES (2,'2018/12/1 17:29');
Insert into T_ClockIn VALUES (2,'2018/12/1 18:01');
Insert into T_ClockIn VALUES (2,'2018/12/2 8:01');
Insert into T_ClockIn VALUES (2,'2018/12/2 9:27');
Insert into T_ClockIn VALUES (2,'2018/12/2 17:59');
Insert into T_ClockIn VALUES (2,'2018/12/2 18:27');

数据如下

3:过程分析

第一步:先将数据利用case when 根据打卡时间分为

1:早打卡     2:晚打卡   0:其余时间打卡     三类

SELECT USERID,checkin,
CASE 
WHEN to_char(checkin,'HH24:MI:SS') BETWEEN '08:00:00' AND '09:00:00' THEN '1' 
WHEN to_char(checkin,'HH24:MI:SS') BETWEEN '16:00:00' AND '18:00:00' THEN '2' 
ELSE '0'
END as 状态
from T_ClockIn

结果

第二步:利用窗口函数over根据用户UserID,打开时间的日期部分作为分组依据,区分有效打卡和重复打卡

select t.*,row_number() 
over (partition by t.userid,t.状态,to_char(checkin,'yyyy-mm-dd') order by t.checkin) as 状态2 
from (
SELECT USERID,checkin,
CASE 
WHEN to_char(checkin,'HH24:MI:SS') BETWEEN '08:00:00' AND '09:00:00' THEN '1' 
WHEN to_char(checkin,'HH24:MI:SS') BETWEEN '16:00:00' AND '18:00:00' THEN '2' 
ELSE '0'
END as 状态
from T_ClockIn) t

结果

难点:可以配合以下SQL结果理解:剔除状态为0非要求时间范围之外打卡记录,剩下的都是时间范围内打卡,

1:有效打卡  2 重复打卡

select t.*,row_number() 
over (partition by t.userid,t.状态,to_char(checkin,'yyyy-mm-dd') order by t.checkin) as 状态2 
from (
SELECT USERID,checkin,
CASE 
WHEN to_char(checkin,'HH24:MI:SS') BETWEEN '08:00:00' AND '09:00:00' THEN '1' 
WHEN to_char(checkin,'HH24:MI:SS') BETWEEN '16:00:00' AND '18:00:00' THEN '2' 
ELSE '0'
END as 状态
from T_ClockIn) t WHERE t.状态>0

结果

第三步

利用状态(区分时间范围内的打卡)  状态2(时间范围内的有效打卡和重复打卡)组合分析判断达到打卡结果统计

   状态=0 then '无效'              状态0直接为无效打卡                         ----->无效
   状态>0 AND a.状态2=1      时间范围内的打卡  并且 有效打卡      ----->有效打卡
   状态>0 AND a.状态2=2      时间范围内的打卡  并且 重复打卡      ----->重复打卡
 最终SQL如下

SELECT
    a.userid,
    a.checkin,
    CASE
        WHEN a.状态 = 0 THEN
            '无效'
        WHEN a.状态 > 0
             AND a.状态2 = 1 THEN
            '有效'
        WHEN a.状态 > 0
             AND a.状态2 = 2 THEN
            '重复'
    END AS 状态
FROM
    (
        SELECT
            t.*,
            ROW_NUMBER() OVER(
                PARTITION BY t.userid, t.状态, to_char(checkin, 'yyyy-mm-dd')
                ORDER BY
                    t.checkin
            ) AS 状态2
        FROM
            (
                SELECT
                    userid,
                    checkin,
                    CASE
                        WHEN to_char(checkin, 'HH24:MI:SS') BETWEEN '08:00:00' AND '09:00:00' THEN
                            '1'
                        WHEN to_char(checkin, 'HH24:MI:SS') BETWEEN '16:00:00' AND '18:00:00' THEN
                            '2'
                        ELSE
                            '0'
                    END AS 状态
                FROM
                    t_clockin
            ) t
    ) a
ORDER BY
    a.userid,
    a.checkin

 结果

 知识点:窗口函数的使用     case when 

评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值