在SQL Server中使用T-SQL获取运行总时间列

时间:2016-07-10 07:11:41

标签: sql-server tsql running-total

我有一个XYZ表,其中包含TIME数据类型列中的员工登录持续时间详细信息。

    EmployeeID | DomainID | LoginDuration
----------------------------------------------------------------
      1111         12       02:32:55:0000000
      1111          4       00:57:17.0000000
      1111         12       01:06:25.0000000
      1111         11       03:31:23.0000000
      2222         11       02:42:17.0000000
      2222          4       03:54:52.0000000
      2222         10       04:08:29.0000000 

除上述列外,我还有LoginTimeStampLoginWeek列,我在JOIN语句中使用这些列。

我正在尝试获取LoginDuration列的运行总计,如下所示:

   EmployeeID | DomainID | HoursBefore      | LoginDuration     | HoursAfter | 
---------------------------------------------------------------------------------
      1111         12      00:00:00.0000000  02:32:55:0000000    **00:00:00.0000000**
      1111          4      02:32:55.0000000  00:57:17.0000000    03:30:12.0000000
      1111         12      03:30:12.0000000  01:06:25.0000000    04:36:37.0000000
      1111         11      04:36:37.0000000  03:31:23.0000000    08:08:00.0000000
      2222         11      00:00:00.0000000  02:42:17.0000000    **00:00:00.0000000**
      2222          4      01:32:31.0000000  03:54:52.0000000    04:14:48.0000000
      2222         10      04:14:48.0000000  04:08:29.0000000    08:09:40.0000000

HoursBefore是HoursAfter的先前值(每位员工的第一行00:00:00)

HoursAfter = HoursBefore + LoginDuration

为此,我编写了以下查询,但是我收到了HoursAfter列的错误。它并没有将每个员工的当前值和先前值相加。

SELECT
    a.EmployeeID,a.LoginDuration,
    COALESCE(CAST(
        DATEADD(ms,
            SUM(DATEDIFF(ms,0,CAST(b.LoginDuration as datetime)))
            , 0)
        as time)
        ,'00:00:00') AS HoursBefore,
    a.LoginDuration as Hours,
    COALESCE(CAST(
        DATEADD(ms,
            SUM(DATEDIFF(ms,0,CAST(b.LoginDuration as datetime)))
            , a.Loginduration)
        as time)
        ,'00:00:00') As HoursAfter
FROM XYZ AS a
LEFT OUTER JOIN XYZ AS b
ON (a.EmployeeID = b.EmployeeID) 
  AND (a.LoginWeek = b.LoginWeek)
  AND (b.LoginTimeStamp < a.LoginTimeStamp)
GROUP BY a.EmployeeID, a.LoginTimeStamp,a.LoginDuration
ORDER BY a.LoginWeek, a.EmployeeID, a.LoginTimeStamp;

我需要查询帮助,以便每个员工的HoursAfter列都合适。

非常感谢任何帮助。 (这是我的第一个查询,如果您可能需要任何进一步的细节,请回复。)

感谢。

2 个答案:

答案 0 :(得分:0)

可惜SQL Server不支持句点数据类型,它会使数学变得更加简单。

但是,它在新版本中对窗口函数有相当好的支持,我们可以用它来解决这个问题:

declare @t table (ID int, EmployeeID int, DomainID int, LoginDuration time)

insert @t
values
(1, 1111,         12,       '02:32:55.0000000'),
(2, 1111,          4,       '00:57:17.0000000'),
(3, 1111,         12,       '01:06:25.0000000'),
(4, 1111,         11,       '03:31:23.0000000'),
(5, 2222,         11,       '02:42:17.0000000'),
(6, 2222,          4,       '03:54:52.0000000'),
(7, 2222,         10,       '04:08:29.0000000')

;with x as (
    select *, dateadd(second, sum(datediff(second, 0, loginduration)) over (partition by employeeid order by id), 0) sum_duration_sec,
        row_number() over (partition by employeeid order by id) rn
    from @t
)
select 
    employeeid, 
    domainid, 
    convert(time, isnull(lag(sum_duration_sec) over (partition by employeeid order by id),0)) hoursbefore,
    loginduration, 
    convert(time, case when rn = 1 then 0 else sum_duration_sec end) hoursafter
from x

我为了简洁而引入了ID列以建立序列,您可能希望使用(LoginWeek,LoginTimestamp)来排序。

另外,不确定在第1行和第5行中HoursAfter应为0的要求 - 如果不是,则完全删除row_number()。

答案 1 :(得分:-1)

使用OUTER APPLY计算After Hours。之前的小时数是减去当前持续时间后的小时数

SELECT  a.EmployeeID, a.DomainID,
        HoursBefore = CONVERT(TIME, DATEADD(SECOND, b.after_secs - DATEDIFF(SECOND, 0, a.LoginDuration), 0)),
        a.LoginDuration,
        HoursAfter  = CONVERT(TIME, DATEADD(SECOND, b.after_secs, 0))
FROM    XYZ AS a
OUTER APPLY
(
        SELECT  after_secs  = SUM(DATEDIFF(SECOND, 0, x.LoginDuration))
        FROM    XYZ x
        WHERE   x.EmployeeID         = a.EmployeeID
        AND     x.LoginWeek          = a.LoginWeek
        AND     x.LoginTimeStamp    <= a.LoginTimeStamp
) b