每两行的DATEDIFF的总和,以分钟为单位

时间:2014-02-03 16:33:40

标签: sql sql-server sql-server-2008 datediff

我正在尝试针对第三方员工时间跟踪数据库运行查询。据我所知,他们不会在一天的员工时间内保持总计。我所拥有的是一系列包含用户ID和时间戳的行。如果我按时间戳排序行,我会有效地获得他们的拳击历史。如果我假设冲头1在,冲头2出来,冲头3在等等,是否有一种有效的方法在几分钟内从每隔一行找到DATEDIFF,然后将它们相加以获得当天的总时间那个员工?

    badge_no punch_timestamp
    11209   1/31/14 7:58 AM
    11209   1/31/14 9:57 AM
    11209   1/31/14 10:00 AM
    11209   1/31/14 10:07 AM

发布后不到2分钟,我发现了这篇帖子: SQL Server find datediff between different rows, sum

我先试试。

2 个答案:

答案 0 :(得分:2)

这是一种相对简单,天真的做法。假设,就像你说的那样,每个“奇数”行都是一个标记,每个“偶数”行都是一个标记,你可以分别抓住奇数行和偶数行并计算每个工作块。请注意,我使用的DateDiff是几分钟(mi),但您可以将其更改为小时/秒/其他:http://technet.microsoft.com/en-us/library/ms189794.aspx

;WITH StartTime AS
(
SELECT
    badge_no,
    punch_timestamp,
    myrow
FROM
(
    SELECT
        badge_no,
        punch_timestamp,
        ROW_NUMBER() OVER (Partition BY badge_no ORDER BY punch_timestamp ASC) as myrow
    FROM #Time
) [t1]
WHERE myrow % 2 = 1 --odd rows
)
,EndTime AS
(
SELECT
    badge_no,
    punch_timestamp,
    myrow - 1 as 'myrow' --Subtract 1 to match up with the odd rows
FROM
(
    SELECT
        badge_no,
        punch_timestamp,
        ROW_NUMBER() OVER (Partition BY badge_no ORDER BY punch_timestamp ASC) as myrow
    FROM #Time
) [t1]
WHERE myrow % 2 = 0 --even rows
)

SELECT
    badge_no,
    SUM(diff) as 'MinutesWorked'
FROM 
(
SELECT
    EndTime.badge_no,
    DATEDIFF(mi, 
             (SELECT TOP 1 
                  punch_timestamp 
              FROM StartTime 
              WHERE StartTime.badge_no = EndTime.badge_no 
                  AND StartTime.myrow = EndTime.myrow), 
             EndTime.punch_timestamp) as 'diff'
FROM EndTime
) [t1]
GROUP BY badge_no

以下是我使用的测试数据:

CREATE TABLE #Time
(
    badge_no nvarchar(10),
    punch_timestamp datetime
)

INSERT INTO #Time VALUES ('100', '2013-01-02 12:01 PM')
INSERT INTO #Time VALUES ('100', '2013-01-02 1:38 PM')
INSERT INTO #Time VALUES ('100', '2013-01-02 2:29 PM')
INSERT INTO #Time VALUES ('100', '2013-01-03 3:01 PM')
INSERT INTO #Time VALUES ('100', '2013-01-03 4:20 PM')
INSERT INTO #Time VALUES ('100', '2013-01-04 12:01 PM')
INSERT INTO #Time VALUES ('100', '2013-01-04 2:01 PM')
INSERT INTO #Time VALUES ('100', '2013-01-04 3:11 PM')
INSERT INTO #Time VALUES ('100', '2013-01-04 4:21 PM')
INSERT INTO #Time VALUES ('100', '2013-01-05 12:01 PM')
INSERT INTO #Time VALUES ('100', '2013-01-05 1:01 PM')
INSERT INTO #Time VALUES ('200', '2013-01-04 2:11 AM')
INSERT INTO #Time VALUES ('200', '2013-01-04 4:34 PM')
INSERT INTO #Time VALUES ('200', '2013-01-05 1:01 AM')
INSERT INTO #Time VALUES ('200', '2013-01-05 4:29 AM')

答案 1 :(得分:1)

使用@DaveZych样本数据我设法使用下面的SQL语句计算出与他相同的结果:

;WITH DataSource ([StartOrEnd], [badge_no], [punch_timestamp]) AS
(
    SELECT ROW_NUMBER() OVER (PARTITION BY [badge_no] ORDER BY [punch_timestamp]) +
           ROW_NUMBER() OVER (PARTITION BY [badge_no] ORDER BY [punch_timestamp])  % 2
          ,[badge_no]
          ,[punch_timestamp]
    FROM #Time
),
TimesPerBadge_No ([badge_no], [StartOrEnd], [Minutes]) AS
(
    SELECT  [badge_no]
           ,[StartOrEnd] 
           ,DATEDIFF(MINUTE, MIN([punch_timestamp]), MAX([punch_timestamp]))
    FROM DataSource
    GROUP BY [badge_no]
            ,[StartOrEnd] 
)
SELECT [badge_no]
      ,SUM([Minutes])
FROM TimesPerBadge_No
GROUP BY [badge_no]

这里可以看到每个CTE的值:

首先,我们需要对每个开始和结束日期进行分组:

 SELECT ROW_NUMBER() OVER (PARTITION BY [badge_no] ORDER BY [punch_timestamp]) +
           ROW_NUMBER() OVER (PARTITION BY [badge_no] ORDER BY [punch_timestamp])  % 2
          ,[badge_no]
          ,[punch_timestamp]
    FROM #Time

enter image description here

现在,我们可以计算每组的分钟差异:

SELECT  [badge_no]
        ,[StartOrEnd] 
        ,DATEDIFF(MINUTE, MIN([punch_timestamp]), MAX([punch_timestamp]))
FROM DataSource
GROUP BY [badge_no]
        ,[StartOrEnd] 

enter image description here

并最终sumarize每个badge_no的分钟数:

SELECT [badge_no]
      ,SUM([Minutes])
FROM TimesPerBadge_No
GROUP BY [badge_no]

enter image description here