【问题标题】:SUM of DATEDIFF in minutes for each 2 rows每 2 行以分钟为单位的 DATEDIFF 总和
【发布时间】:2014-02-27 05:58:08
【问题描述】:

我正在尝试针对第 3 方员工时间跟踪数据库运行查询。据我所知,他们并没有全天记录员工时间的总和。我所拥有的是一系列包含用户 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

我会先试一试。

【问题讨论】:

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


    【解决方案1】:

    这是一种相对简单、幼稚的做法。假设,就像你说的那样,每个“奇数”行是一个印记,每个“偶数”行是一个印记,你可以分别获取奇数行和偶数行并计算每个工作块。请注意,我使用的 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')
    

    【讨论】:

      【解决方案2】:

      使用@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
      

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

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

      最后总结每个badge_no的分钟数:

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

      【讨论】:

        猜你喜欢
        • 2019-05-08
        • 1970-01-01
        • 2014-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多