修复记录重复时交叉应用行

时间:2017-08-29 07:30:24

标签: sql-server tsql cross-apply

我有一个EVENT表,其中包含进入和退出事件。我用这个程序计算工作时间:

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)

例如,某些Employee有两个enter和两个退出事件,它完美无缺。但是,如果有一个退出和两个输入事件,它就不会像我想要的那样工作。

示例:员工XXX于05:44开始工作,然后他于06:28退出。后来他在06:50回来,并在12:33再次退出。此过程应返回@worktime等于387分钟。

第二天他犯了一个错误,他在06:00来上班,但在EVENTS表中,有两个相同的记录。他在14:00退出(exit表中只有1 EVENT个记录。程序返回960分钟。如果它返回480,我想。

如果输入事件的数量不等于退出事件的数量(例如:2进入和1退出),如何修复交叉申请?

图片示例:

下面的例子很完美。

Working Example

选定的行(1,4,5,8)被传递给程序。 ControlPointId = 6是入口点,ControlPointId = 3是退出点。 EventTypeId = 1是输入事件,EventTypeId = 2是退出。

但这不起作用:

Not Working

在这种情况下,ControlPointId = 64是入口点,ControlPointId = 56是出口点。我们可以看到,这个Employee犯了错误,ControlPoint读了两次卡片,所以有两个入场事件和一个退出事件。

我应该如何更改程序?当出现像这样的错误时(或者在相反的情况下:1个条目和2个退出事件),它应该只进行第一次进入事件。

1 个答案:

答案 0 :(得分:1)

你可以试试这个。如果不同的条目事件具有相同的退出事件,我将使用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)