修复记录重复时交叉应用行
Fix cross applying rows when records are duplicated
我有一个 EVENT
table,其中包含进入和退出事件。我用这个程序计算工作时间:
SET @worktime = (SELECT SUM(mins)
FROM
(SELECT
entry.EmployeeId, entry.DateTime AS EntryDateTime,
[exit].DateTime AS ExitDateTime, DATEDIFF(MINUTE, entry.DateTime, [exit].DateTime) AS mins
FROM
Events entry
CROSS APPLY
(SELECT TOP 1 e.DateTime
FROM Events e
WHERE e.EmployeeId = entry.EmployeeId
AND e.DateTime > entry.DateTime
AND e.EventTypeID = 2
AND CAST(e.DateTime AS DATE) = CAST(@data AS DATE)
AND e.ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' EXIT')
ORDER BY e.DateTime ASC) AS [exit]
WHERE
entry.EventTypeId = 1
AND EmployeeId = @code
AND CAST(entry.DateTime AS DATE) = CAST(@data AS DATE)
AND ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' ENTRY')
AND CAST(entry.[DateTime] AS DATE) = CAST(@data AS DATE)) AS input
GROUP BY EmployeeId)
例如,某些员工有两个进入和两个退出事件,它工作得很好。但是,如果有一个退出事件和两个进入事件,它就不会像我想的那样工作。
示例:员工 XXX 在 05:44 上班,然后在 06:28 下班。稍后他在 06:50 返回并在 12:33 再次退出。这个程序应该return@worktime
等于387分钟。
第二天他犯了一个错误,他来到06:00上班,但是在EVENTS
table,有两条相同的记录。他在 14:00 退出(EVENT
table 中只有 1 exit
条记录)。程序 returns 960 分钟。我想 returns 480.
当进入事件的数量不等于退出事件的数量(例如:2 次进入和 1 次退出)时,我该如何修复交叉应用?
图片示例:
下面的例子很完美。
选定的行 (1,4,5,8) 已传递给过程。 ControlPointId = 6
是入口点,ControlPointId = 3
是出口点。 EventTypeId = 1
是进入事件,EventTypeId = 2
是退出事件。
但这不起作用:
在这种情况下,ControlPointId = 64
是入口点,ControlPointId = 56
是出口点。我们可以看到,这个Employee
犯了错误,ControlPoint
读了他的卡片两次,所以有2个进入事件和1个退出事件。
我应该如何更改程序?当出现这样的错误时(或相反的情况:1 次进入和 2 次退出事件),应该只需要第一个进入事件。
你可以试试这个。如果不同的进入事件有相同的退出事件,我使用 ROW_NUMBER
保留第一个进入
SET @worktime = (SELECT SUM(mins)
FROM
(SELECT
entry.EmployeeId, entry.DateTime AS EntryDateTime,
[exit].DateTime AS ExitDateTime,
DATEDIFF(MINUTE, entry.DateTime, [exit].DateTime) AS mins,
RN = ROW_NUMBER () OVER (PARTITION BY [exit].EventID ORDER BY entry.DateTime)
FROM
Events entry
CROSS APPLY
(SELECT TOP 1 e.DateTime, e.EventID
FROM Events e
WHERE e.EmployeeId = entry.EmployeeId
AND e.DateTime > entry.DateTime
AND e.EventTypeID = 2
AND CAST(e.DateTime AS DATE) = CAST(@data AS DATE)
AND e.ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' EXIT')
ORDER BY e.DateTime ASC) AS [exit]
WHERE
entry.EventTypeId = 1
AND EmployeeId = @code
AND CAST(entry.DateTime AS DATE) = CAST(@data AS DATE)
AND ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' ENTRY')
AND CAST(entry.[DateTime] AS DATE) = CAST(@data AS DATE)) AS input
WHERE RN = 1
GROUP BY EmployeeId)
我有一个 EVENT
table,其中包含进入和退出事件。我用这个程序计算工作时间:
SET @worktime = (SELECT SUM(mins)
FROM
(SELECT
entry.EmployeeId, entry.DateTime AS EntryDateTime,
[exit].DateTime AS ExitDateTime, DATEDIFF(MINUTE, entry.DateTime, [exit].DateTime) AS mins
FROM
Events entry
CROSS APPLY
(SELECT TOP 1 e.DateTime
FROM Events e
WHERE e.EmployeeId = entry.EmployeeId
AND e.DateTime > entry.DateTime
AND e.EventTypeID = 2
AND CAST(e.DateTime AS DATE) = CAST(@data AS DATE)
AND e.ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' EXIT')
ORDER BY e.DateTime ASC) AS [exit]
WHERE
entry.EventTypeId = 1
AND EmployeeId = @code
AND CAST(entry.DateTime AS DATE) = CAST(@data AS DATE)
AND ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' ENTRY')
AND CAST(entry.[DateTime] AS DATE) = CAST(@data AS DATE)) AS input
GROUP BY EmployeeId)
例如,某些员工有两个进入和两个退出事件,它工作得很好。但是,如果有一个退出事件和两个进入事件,它就不会像我想的那样工作。
示例:员工 XXX 在 05:44 上班,然后在 06:28 下班。稍后他在 06:50 返回并在 12:33 再次退出。这个程序应该return@worktime
等于387分钟。
第二天他犯了一个错误,他来到06:00上班,但是在EVENTS
table,有两条相同的记录。他在 14:00 退出(EVENT
table 中只有 1 exit
条记录)。程序 returns 960 分钟。我想 returns 480.
当进入事件的数量不等于退出事件的数量(例如:2 次进入和 1 次退出)时,我该如何修复交叉应用?
图片示例:
下面的例子很完美。
选定的行 (1,4,5,8) 已传递给过程。 ControlPointId = 6
是入口点,ControlPointId = 3
是出口点。 EventTypeId = 1
是进入事件,EventTypeId = 2
是退出事件。
但这不起作用:
在这种情况下,ControlPointId = 64
是入口点,ControlPointId = 56
是出口点。我们可以看到,这个Employee
犯了错误,ControlPoint
读了他的卡片两次,所以有2个进入事件和1个退出事件。
我应该如何更改程序?当出现这样的错误时(或相反的情况:1 次进入和 2 次退出事件),应该只需要第一个进入事件。
你可以试试这个。如果不同的进入事件有相同的退出事件,我使用 ROW_NUMBER
SET @worktime = (SELECT SUM(mins)
FROM
(SELECT
entry.EmployeeId, entry.DateTime AS EntryDateTime,
[exit].DateTime AS ExitDateTime,
DATEDIFF(MINUTE, entry.DateTime, [exit].DateTime) AS mins,
RN = ROW_NUMBER () OVER (PARTITION BY [exit].EventID ORDER BY entry.DateTime)
FROM
Events entry
CROSS APPLY
(SELECT TOP 1 e.DateTime, e.EventID
FROM Events e
WHERE e.EmployeeId = entry.EmployeeId
AND e.DateTime > entry.DateTime
AND e.EventTypeID = 2
AND CAST(e.DateTime AS DATE) = CAST(@data AS DATE)
AND e.ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' EXIT')
ORDER BY e.DateTime ASC) AS [exit]
WHERE
entry.EventTypeId = 1
AND EmployeeId = @code
AND CAST(entry.DateTime AS DATE) = CAST(@data AS DATE)
AND ControlPointID IN (SELECT ControlPointID
FROM ControlPoints
INNER JOIN dbo.Split(RIGHT(@rcp, LEN(@rcp) - 2), ';') AS split ON ControlPoints.NAme = split.Data + ' ENTRY')
AND CAST(entry.[DateTime] AS DATE) = CAST(@data AS DATE)) AS input
WHERE RN = 1
GROUP BY EmployeeId)