如何将SQL打卡表的In/Out时间拆分至不同列创建视图?
实现打卡记录进出时间配对的SQL视图
要实现将打卡记录中的入卡(I)和出卡(O)记录配对,生成包含姓名、入卡时间、出卡时间的视图,且确保出卡时间在入卡时间的0-16小时范围内,可以通过以下两种方式实现:
方法一:基础自连接(适用于单进单出场景)
如果员工每天只有一次入卡和一次出卡记录,直接使用表自连接即可:
CREATE VIEW vw_AttendanceRecords AS SELECT i.Name, i.TimeStamp AS [TimeStamp IN], o.TimeStamp AS [Timestamp OUT] FROM 打卡记录表 i INNER JOIN 打卡记录表 o ON i.Name = o.Name AND o.TimeStamp >= i.TimeStamp AND DATEDIFF(HOUR, i.TimeStamp, o.TimeStamp) BETWEEN 0 AND 16 WHERE i.[In-Out] = 'I' AND o.[In-Out] = 'O';
代码说明:
- 用别名
i标记入卡记录,o标记出卡记录,通过Name关联同一名员工的记录 - 筛选条件限定
i的In-Out值为I,o的为O - 使用
DATEDIFF(HOUR, ...)确保出卡时间在入卡时间的0到16小时范围内,同时通过o.TimeStamp >= i.TimeStamp避免时间顺序颠倒的错误配对
方法二:窗口函数配对(适用于多进多出场景)
如果员工存在同一天多次进出的情况,用窗口函数给每个员工的入、出记录按时间排序,再按序号配对,能更准确地对应顺序的进出:
CREATE VIEW vw_AttendanceRecords AS WITH InRecords AS ( SELECT Name, TimeStamp AS InTime, -- 按员工分组,给入卡记录按时间排序编号 ROW_NUMBER() OVER (PARTITION BY Name ORDER BY TimeStamp) AS RecordSeq FROM 打卡记录表 WHERE [In-Out] = 'I' ), OutRecords AS ( SELECT Name, TimeStamp AS OutTime, -- 按员工分组,给出卡记录按时间排序编号 ROW_NUMBER() OVER (PARTITION BY Name ORDER BY TimeStamp) AS RecordSeq FROM 打卡记录表 WHERE [In-Out] = 'O' ) SELECT ir.Name, ir.InTime AS [TimeStamp IN], orr.OutTime AS [Timestamp OUT] FROM InRecords ir INNER JOIN OutRecords orr ON ir.Name = orr.Name AND ir.RecordSeq = orr.RecordSeq WHERE DATEDIFF(HOUR, ir.InTime, orr.OutTime) BETWEEN 0 AND 16;
代码说明:
- 先用CTE分别提取入卡和出卡记录,并用
ROW_NUMBER()给每个员工的记录按时间顺序编号 - 通过员工姓名和记录序号关联对应的入、出记录,保证顺序匹配
- 最后用
DATEDIFF过滤时差在0-16小时内的有效配对
内容的提问来源于stack exchange,提问作者Andy Jansen
相关产品推荐
相关产品推荐

