需要匹配时钟与时钟,同一天的多个时钟SQL

发布于 2025-01-20 00:00:58 字数 6578 浏览 5 评论 0原文

我试图让上班时间和下班时间相互对应,以便我可以计算工作时间/休息时间/工作时间内的工作时间等。我有一个“时钟”表,如下所示:

MOCK数据:

Clock_ID员工_ID办公室Clock_DateClock_TimeActivityID
183比勒陀利亚 CBD29/03/202206:43:001
255比勒陀利亚 CBD29/03/202206:45:001
354比勒陀利亚中央商务区29/03/202207:00:001
480比勒陀利亚中央商务区29/03/202207:00:001
575比勒陀利亚中央商务区29/03/202207:05:001
654比勒陀利亚中央商务区29/03/202210:59:002
754比勒陀利亚中央商务区29/03/202211:50:001
855比勒陀利亚中央商务区29/03/202212:18:002
955比勒陀利亚中央商务区29/ 03/202212:30:001
1083比勒陀利亚中央商务区29/03/202213:03:002
1180比勒陀利亚中央商务区29/03/202213:04:002
1283比勒陀利亚中央商务区29/03/202213:39:001
1380比勒陀利亚中央商务区29/03/202213:39:001
1475比勒陀利亚中央商务区29/03/202215:59:002
1554比勒陀利亚中央商务区29/03/202216:00:002
1683比勒陀利亚中央商务区29/03/202216:00:002
1780比勒陀利亚中央商务区29/03/202216:00:002
1855比勒陀利亚中央商务区29/03/202216:00:002
1983比勒陀利亚中央商务区30/03/202206:46:001
2055比勒陀利亚中央商务区30 /03/202206:51:001
2180比勒陀利亚中央商务区30/03/202206:54:001
2254比勒陀利亚中央商务区30/03/202206:54:001
2354比勒陀利亚中央商务区30/03/202211:24:002
2454比勒陀利亚中央商务区30/03/202212:11:001
2580比勒陀利亚中央商务区30/03/202213:03:002
2680比勒陀利亚中央商务区30/03/202214:10:001
2754比勒陀利亚中央商务区30/03/202216:01:002
2880比勒陀利亚中央商务区30/03/202216:01:002
2983比勒陀利亚中央商务区30/03/202216:01:002
3055比勒陀利亚中央商务区30/03/202216:05:002
3183比勒陀利亚中央商务区31 /03/202206:48:001
3255比勒陀利亚中央商务区31/03/202206:53:001
3354比勒陀利亚中央商务区31/03/202206:55:001
3480比勒陀利亚中央商务区31/03/202207:09:001
3554比勒陀利亚中央商务区31/03/202212:02:002
3654比勒陀利亚中央商务区31/03/202212:09:001
3783比勒陀利亚中央商务区31/03/202212:34:002
3880比勒陀利亚中央商务区31/03/202212:34:002
3983比勒陀利亚中央商务区31/03/202213:09:001
4080比勒陀利亚中央商务区31/03/202213:09:001
4155比勒陀利亚中央商务区31/03/202213:32:002
4254比勒陀利亚中央商务区31 /03/202215:56:002

ActivityID 确定它是“时钟输入”还是“时钟输出”

我已使用哈希表将任何给定 Employee_ID 的数据分成 #clockIN 和 #clockOUT 表,如下所示:

# ClockIN

在此处输入图像描述

#ClockOUT

在此处输入图像描述

我尝试使用的内连接表上的“Clock_Date”将时钟输入与时钟输出相对应,但由于员工可以在一天内多次输入和输出时钟,因此我会为一个时钟输入获得多个时钟输出:请参见下文

: sstatic.net/AFib1.png" rel="nofollow noreferrer">在此处输入图像描述

作为可以看到,记录匹配不正确,并且是刚刚加入的日期。

我想不出正确加入它们的方法,即 7:30 的 ClockIn 必须与当天最早的时钟加入,并且当天的下一个 ClockIN 必须是第二个最早的 ClockIN,它必须与第二个最早的时钟加入OUT 等。

我必须使用游标吗?如果是这样,我该如何实施?

我将介绍到目前为止我所使用的所有 SQL。

Drop Table #ClockIn
Drop Table #ClockOut
DROP Table #SortedTimes
DROP Table #WorkBoundries

SELECT Clock_ID, Clock_Date AS Date, Clock_Time
    INTO #ClockIn 
    FROM Clocking
    WHERE Employee_ID = 82 AND ActivityID = 1
    SELECT * FROM #ClockIn

SELECT Clock_ID, Clock_Date AS Date, Clock_Time
    INTO #ClockOut 
    FROM Clocking
    WHERE Employee_ID = 82 AND ActivityID = 2
    SELECT * FROM #ClockOut
            
SELECT #ClockIn.Clock_Time As clockIN, #ClockOut.Clock_Time as ClockOUT, #ClockIn.Date INTO #SortedTimes
FROM #ClockIn
INNER JOIN #ClockOut On #ClockOut.Date = #ClockIN.Date
ORDER BY #ClockIn.Date ASC

SELECT * FROM #SortedTimes

SELECT MIN(clockIn)As TimeIn, MAX(ClockOUT) As TimeOut, [Date] As DayWorked INTO #WorkBoundries
FROM #SortedTimes
GROUP BY [Date]
SELECT * FROM #WorkBoundries

#WorkBoundries 只是为了查看该人是否在工作时间内打卡上班/下班。

预先感谢您的任何帮助

I'm trying to get the clock in and clock out times to correspond to each other so that I can calculate hours worked/amount of breaks/time worked within working hours etc. I have a 'Clocking' table that looks like this:

MOCK DATA:

Clock_IDEmployee_IDOfficeClock_DateClock_TimeActivityID
183Pretoria CBD29/03/202206:43:001
255Pretoria CBD29/03/202206:45:001
354Pretoria CBD29/03/202207:00:001
480Pretoria CBD29/03/202207:00:001
575Pretoria CBD29/03/202207:05:001
654Pretoria CBD29/03/202210:59:002
754Pretoria CBD29/03/202211:50:001
855Pretoria CBD29/03/202212:18:002
955Pretoria CBD29/03/202212:30:001
1083Pretoria CBD29/03/202213:03:002
1180Pretoria CBD29/03/202213:04:002
1283Pretoria CBD29/03/202213:39:001
1380Pretoria CBD29/03/202213:39:001
1475Pretoria CBD29/03/202215:59:002
1554Pretoria CBD29/03/202216:00:002
1683Pretoria CBD29/03/202216:00:002
1780Pretoria CBD29/03/202216:00:002
1855Pretoria CBD29/03/202216:00:002
1983Pretoria CBD30/03/202206:46:001
2055Pretoria CBD30/03/202206:51:001
2180Pretoria CBD30/03/202206:54:001
2254Pretoria CBD30/03/202206:54:001
2354Pretoria CBD30/03/202211:24:002
2454Pretoria CBD30/03/202212:11:001
2580Pretoria CBD30/03/202213:03:002
2680Pretoria CBD30/03/202214:10:001
2754Pretoria CBD30/03/202216:01:002
2880Pretoria CBD30/03/202216:01:002
2983Pretoria CBD30/03/202216:01:002
3055Pretoria CBD30/03/202216:05:002
3183Pretoria CBD31/03/202206:48:001
3255Pretoria CBD31/03/202206:53:001
3354Pretoria CBD31/03/202206:55:001
3480Pretoria CBD31/03/202207:09:001
3554Pretoria CBD31/03/202212:02:002
3654Pretoria CBD31/03/202212:09:001
3783Pretoria CBD31/03/202212:34:002
3880Pretoria CBD31/03/202212:34:002
3983Pretoria CBD31/03/202213:09:001
4080Pretoria CBD31/03/202213:09:001
4155Pretoria CBD31/03/202213:32:002
4254Pretoria CBD31/03/202215:56:002

The ActivityID determines whether it is a 'Clock IN' or 'Clock OUT'

I have used hash tables to separate the data into #clockIN and #clockOUT tables for any given Employee_ID as seen below:

#ClockIN

enter image description here

#ClockOUT

enter image description here

I tried using an inner join on the 'Clock_Date' on the tables to correspond clockINs to clockOUTs, but I get multiple clockOUTS for one clockIN due to the fact that employees can clockIN and OUT multiple times in a day: See below:

enter image description here

As you can see, the records are matched incorrectly, and a just joined on the date.

I cannot think of a way to correctly join them I.e ClockIn at 7:30 must be joined with the EARLIEST clock out on the same day and the next clockIN for that day must be the second earliest ClockIN which must be joined with the second earliest Clock OUT etc.

Would I have to use a cursor? if so, how could I implement that?

I will past all the SQL I used to get to this point.

Drop Table #ClockIn
Drop Table #ClockOut
DROP Table #SortedTimes
DROP Table #WorkBoundries

SELECT Clock_ID, Clock_Date AS Date, Clock_Time
    INTO #ClockIn 
    FROM Clocking
    WHERE Employee_ID = 82 AND ActivityID = 1
    SELECT * FROM #ClockIn

SELECT Clock_ID, Clock_Date AS Date, Clock_Time
    INTO #ClockOut 
    FROM Clocking
    WHERE Employee_ID = 82 AND ActivityID = 2
    SELECT * FROM #ClockOut
            
SELECT #ClockIn.Clock_Time As clockIN, #ClockOut.Clock_Time as ClockOUT, #ClockIn.Date INTO #SortedTimes
FROM #ClockIn
INNER JOIN #ClockOut On #ClockOut.Date = #ClockIN.Date
ORDER BY #ClockIn.Date ASC

SELECT * FROM #SortedTimes

SELECT MIN(clockIn)As TimeIn, MAX(ClockOUT) As TimeOut, [Date] As DayWorked INTO #WorkBoundries
FROM #SortedTimes
GROUP BY [Date]
SELECT * FROM #WorkBoundries

The #WorkBoundries is just to see if the person is clocking IN/OUT within their work hours or not.

Thank you in advance for any assistance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

城歌 2025-01-27 00:00:58

也许这可以帮助您

select e.empid,
       e.clockdate,
       e.clocktime as starttime,
       o.clocktime as endtime
from   emp e
  outer apply (select top 1 e2.clocktime 
               from   emp e2 
               where  e2.empid = e.empid
               and    e2.activity = 2
               and    e2.clockdate = e.clockdate
               and    e2.clocktime > e.clocktime
               order by e2.clocktime
              ) o
where  e.activity = 1
order by e.empid, e.clocktime

a5c3a84446f929dd2c50d115115ca0303030ce57fiddle=
amp& -03-2906:45:00.000000012:18:00.0000000
552022-03-2912:30:00.0000000null
832022-03-2906:43:00.000000013:03:03:00.00.00.0000 000
832022-03-2913: 00.0000 000 39:00.000000016:00:00.0000000

Maybe this can help you

select e.empid,
       e.clockdate,
       e.clocktime as starttime,
       o.clocktime as endtime
from   emp e
  outer apply (select top 1 e2.clocktime 
               from   emp e2 
               where  e2.empid = e.empid
               and    e2.activity = 2
               and    e2.clockdate = e.clockdate
               and    e2.clocktime > e.clocktime
               order by e2.clocktime
              ) o
where  e.activity = 1
order by e.empid, e.clocktime

DBFiddle here

it results in this

empidclockdatestarttimeendtime
552022-03-2906:45:00.000000012:18:00.0000000
552022-03-2912:30:00.0000000null
832022-03-2906:43:00.000000013:03:00.0000000
832022-03-2913:39:00.000000016:00:00.0000000
-黛色若梦 2025-01-27 00:00:58

您可以使用窗口函数在基表的单次扫描中执行此操作,并且无需连接:

WITH NextValues AS (
    SELECT *,
      NextClockOut = LEAD(CASE WHEN c.ActivityID = 2 THEN c.Clock_Time END)
        OVER (PARTITION BY c.Office, c.Employee_ID, c.Clock_Date
             ORDER BY c.Clock_Time)
    FROM Clocking c
)
SELECT
  nv.Employee_ID,
  nv.Office,
  nv.Clock_Date,
  ClockIn = nv.Clock_Time,
  ClockOut = nv.NextClockOut
FROM NextValues nv
WHERE nv.ActivityID = 1;

db<>fiddle

You can do this in a single scan of the base table, and no joins, by using window functions:

WITH NextValues AS (
    SELECT *,
      NextClockOut = LEAD(CASE WHEN c.ActivityID = 2 THEN c.Clock_Time END)
        OVER (PARTITION BY c.Office, c.Employee_ID, c.Clock_Date
             ORDER BY c.Clock_Time)
    FROM Clocking c
)
SELECT
  nv.Employee_ID,
  nv.Office,
  nv.Clock_Date,
  ClockIn = nv.Clock_Time,
  ClockOut = nv.NextClockOut
FROM NextValues nv
WHERE nv.ActivityID = 1;

db<>fiddle

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文