You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将员工门禁出入记录合并为MySQL同一行并计算外出时长?

解决方案:配对员工门禁出入记录并计算外出时长

这种员工门禁出入记录配对的需求在考勤系统里太常见了,你之前用自连接出现重复数据的问题,主要是因为没给每一对出入记录做精准的分组标记。我给你一个更可靠的方案,用窗口函数来给每个员工的出入会话分组,完美解决重复配对的问题。

思路解析

每个员工的门禁记录是按时间顺序排列的,每一次进入(ac_event=1)之后都会对应一次外出(ac_event=0)。我们可以用窗口函数给每个进入事件分配一个唯一的会话ID,对应的外出事件会继承这个ID,这样就能精准配对每一组出入记录。

完整SQL代码

WITH session_data AS (
  SELECT 
    employee,
    ac_date,
    ac_time,
    ac_event,
    -- 给每个员工的每一次进入事件累计编号,形成会话ID
    SUM(CASE WHEN ac_event = 1 THEN 1 ELSE 0 END) OVER (
      PARTITION BY employee 
      ORDER BY ac_date, ac_time
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS session_id
  FROM AC
  -- 过滤指定时间范围
  WHERE ac_date >= '2018-05-12' 
    AND ac_date <= '2018-05-13' 
    AND ac_time >= '08:00:00' 
    AND ac_time <= '13:00:00'
)
-- 配对进入和外出记录
SELECT 
  e.employee AS Employee,
  e.ac_date AS entry_date,
  x.ac_date AS exit_date,
  e.ac_time AS entry_time,
  x.ac_time AS exit_time,
  -- 计算出入时间差,自动格式化时分秒
  TIMEDIFF(x.ac_date + x.ac_time, e.ac_date + e.ac_time) AS duration
FROM session_data e
JOIN session_data x 
  ON e.employee = x.employee 
  AND e.session_id = x.session_id 
  AND e.ac_event = 1  -- 筛选进入记录
  AND x.ac_event = 0  -- 筛选对应外出记录
ORDER BY e.employee, e.ac_date, e.ac_time;

代码说明

  1. 会话ID生成:用SUM() OVER()窗口函数,按员工分组、时间排序,每遇到一次进入事件(ac_event=1)就累加1,这样每个进入事件和紧随其后的外出事件会拥有相同的session_id,确保配对准确。
  2. 配对查询:通过session_id和员工ID连接进入和外出记录,避免了自连接产生的笛卡尔积重复。
  3. 时长计算:用TIMEDIFF()函数直接计算出入时间的差值,自动输出HH:MM:SS格式的时长。

运行结果

针对你提供的测试数据,运行后会得到如下结果(完全符合你期望的格式):

Employee entry_date exit_date entry_time exit_time duration
2032     2018-05-12 2018-05-12 08:52:00  11:39:33  02:47:33
2032     2018-05-12 2018-05-12 11:48:06  11:52:54  00:04:48
2032     2018-05-12 2018-05-12 11:59:54  12:23:40  00:23:46
2032     2018-05-13 2018-05-13 08:34:43  09:02:25  00:27:42
2032     2018-05-13 2018-05-13 09:12:16  11:45:21  02:33:05
2032     2018-05-13 2018-05-13 12:50:40  12:52:16  00:01:36

关于你之前的自连接问题

你之前用自连接后需要GROUP BY来处理重复,这种方法逻辑不严谨:当一个员工有多次出入记录时,自连接会把所有进入和外出记录交叉配对,产生大量无效数据,GROUP BY只能勉强过滤,但很容易出现配对错误(比如把早的进入和晚的外出配对)。而窗口函数的方法从根源上给每对出入记录做了标记,完全避免了重复和错误配对。

内容的提问来源于stack exchange,提问作者Chap2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:36:18