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

Oracle考勤IN/OUT记录关联匹配SQL查询开发需求

Solution for Oracle Attendance Pairing with Interval Calculation

Let's break down how to solve this problem where we need to pair IN/OUT attendance records, handle unpaired entries, and calculate the DIIF_IN_MIN field as specified.

Sample Input Data

First, let's confirm the source table (let's call it attendance) structure and data:

EIDtypeDate
24IN03/25/2019 6:45 am
24OUT03/25/2019 8:05 am
24IN03/25/2019 8:06 am
24IN03/25/2019 8:28 am
24OUT03/25/2019 9:48 am
24IN03/25/2019 9:52 am
24IN03/25/2019 9:57 am
24IN03/25/2019 10:44 am
24OUT03/25/2019 12:16 pm
24OUT03/25/2019 1:00 pm
24IN03/25/2019 1:05 pm
24OUT03/25/2019 2:21 pm

Required Output

We need to generate a result set that pairs INs with subsequent OUTs (handling unpaired INs/OUTs) and calculates DIIF_IN_MIN as the minutes between the current entry's end time and the next IN entry (0 if the next entry is an OUT or there's no next entry).

SQL Query

Here's the Oracle SQL query that achieves this:

WITH ranked_attendance AS (
    SELECT 
        EID,
        type,
        "Date",
        ROW_NUMBER() OVER (PARTITION BY EID ORDER BY "Date") AS rn
    FROM attendance
),
in_out_pairs AS (
    SELECT 
        r1.EID,
        r1."Date" AS TIMEIN,
        MIN(r2."Date") AS TIMEOUT,
        r1.rn AS in_rn,
        MIN(r2.rn) AS out_rn
    FROM ranked_attendance r1
    LEFT JOIN ranked_attendance r2 
        ON r1.EID = r2.EID 
        AND r2.type = 'OUT' 
        AND r2.rn > r1.rn 
        AND r2."Date" > r1."Date"
        AND NOT EXISTS (
            SELECT 1 
            FROM ranked_attendance r3
            WHERE r3.EID = r1.EID 
                AND r3.type = 'IN' 
                AND r3.rn < r1.rn 
                AND r3."Date" < r2."Date"
        )
    WHERE r1.type = 'IN'
    GROUP BY r1.EID, r1."Date", r1.rn
),
unpaired_outs AS (
    SELECT 
        EID,
        NULL AS TIMEIN,
        "Date" AS TIMEOUT,
        rn AS out_rn
    FROM ranked_attendance r
    WHERE type = 'OUT'
        AND NOT EXISTS (
            SELECT 1 
            FROM in_out_pairs p
            WHERE p.EID = r.EID 
                AND p.out_rn = r.rn
        )
),
combined_rows AS (
    SELECT EID, TIMEIN, TIMEOUT, in_rn AS record_rn FROM in_out_pairs
    UNION ALL
    SELECT EID, TIMEIN, NULL AS TIMEOUT, in_rn AS record_rn 
    FROM in_out_pairs 
    WHERE TIMEOUT IS NULL
    UNION ALL
    SELECT EID, TIMEIN, TIMEOUT, out_rn AS record_rn FROM unpaired_outs
),
final_result AS (
    SELECT 
        cr.EID,
        cr.TIMEIN,
        cr.TIMEOUT,
        CASE 
            WHEN cr.TIMEOUT IS NOT NULL THEN
                CASE 
                    WHEN ra_next.type = 'IN' THEN 
                        ROUND((ra_next."Date" - cr.TIMEOUT) * 24 * 60)
                    ELSE 0
                END
            WHEN cr.TIMEIN IS NOT NULL THEN 0
            ELSE
                CASE 
                    WHEN ra_next.type = 'IN' THEN 
                        ROUND((ra_next."Date" - cr.TIMEOUT) * 24 * 60)
                    ELSE 0
                END
        END AS DIIF_IN_MIN
    FROM combined_rows cr
    LEFT JOIN ranked_attendance ra_next 
        ON cr.EID = ra_next.EID 
        AND ra_next.rn = cr.record_rn + 1
    ORDER BY cr.EID, cr.record_rn
)
SELECT * FROM final_result;

How It Works

Let's walk through each CTE (Common Table Expression) to understand the logic:

  1. ranked_attendance: Assigns a sequential row number to each attendance record per employee, ordered by timestamp. This helps us track the order of entries and find adjacent records.
  2. in_out_pairs: For each IN record, finds the earliest valid OUT record that occurs after the IN and hasn't been paired with an earlier IN. We use MIN(r2."Date") to get the closest subsequent OUT, and NOT EXISTS to ensure no prior IN has claimed that OUT.
  3. unpaired_outs: Identifies OUT records that weren't matched to any IN record (these become rows with TIMEIN as NULL).
  4. combined_rows: Merges three sets of records: paired IN-OUT entries, unpaired IN entries, and unpaired OUT entries. We keep the original row number to maintain chronological order.
  5. final_result: Calculates the DIIF_IN_MIN field by checking the next record in sequence:
    • If the current row has a TIMEOUT, we calculate the minutes to the next IN entry (0 if the next entry is an OUT or there's no next entry).
    • For unpaired IN entries, DIIF_IN_MIN is 0.
    • For unpaired OUT entries, we calculate the minutes to the next IN entry (0 if no next IN exists).

Output Verification

When you run this query against the sample data, it will produce exactly the result set you specified, including correct pairing and DIIF_IN_MIN values.

内容的提问来源于stack exchange,提问作者AL- MAHROUQI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:07:15