SQL Server 2014中的条件SUM

时间:2015-12-16 17:27:46

标签: sql sql-server

我正在使用SQL Server 2014.当我测试我的代码时,我发现了一个问题。 假设最长个人小时为80小时。

SELECT    
    lsm.EmployeeName,
    pd.absenceDate,
    pd.amountInDays * 8 AS [HoursReported],
    pd.status,
    (SUM(CASE WHEN pd.[status]='App' THEN (pd.amountInDays * 8)
              ELSE 0 END) OVER (partition by lsm.[EmployeeName] order by pd.absenceDate)) AS [TotalUsedHours]
          ( @maxPSHours ) - (sum(
              CASE WHEN pd.[status]='App' THEN (pd.amountInDays * 8)
                   ELSE 0 END)
          over (
              partition by  lsm.[EmployeeName] order by pd.absenceDate)) AS [TotalRemainingHours]
FROM    
    [LocationStaffMembers] lsm 
INNER JOIN 
    [PersonalDays] pd ON lsm.staffMemberId = pd.staffMemberId 

此查询返回以下结果:

EmployeeName AbsenceDate HoursReported   Status     TotalUsdHrs  TotalRemingHrs
 X            11/11/2015       4         approved     4             76
 X            11/15/2015       8         approved     12            68
 X            11/20/2015       2         decline      14            66
 X            11/20/2015       2         approved     14            66

因此,查询适用于不同的状态。前2行很好。但是,当员工在一天内执行多项操作(拒绝,批准等)时,我的查询仅显示当天的总使用量和总剩余时间。

这是预期的结果。

EmployeeName AbsenceDate HoursReported   Status     TotalUsdHrs  TotalRemingHrs
 X            11/11/2015       4         approved     4             76
 X            11/15/2015       8         approved     12            68
 X            11/20/2015       2         decline      12            68
 X            11/20/2015       2         approved     14            66

1 个答案:

答案 0 :(得分:1)

您正在执行累积总和,根据AbsenceDatesum(...) over (partition by ... order by pd.absenceDate)的顺序返回结果。但是你的最后2条记录的日期完全相同(11/20/2015) - 至少,根据你向我们展示的内容。这造成了歧义。

因此,在计算累积总和时,SQL Server正在2 approved hours处理2 declined hours行之前是完全可以想象的,也是合法的 - 这将解释您当前的结果 - 尽管行本身以不同的顺序返回给您(顺便说一句,考虑在查询中添加order by子句,否则,行本身的顺序无法保证)。 / p>

如果2行确实共享完全相同的日期,那么您必须找到第2列以消除歧义并将其添加到累积order by中的sum子句中窗口功能。也许您可以添加一个可以订购的时间戳字段。

或者,当declined相同时,您可能始终希望在approved状态之前考虑AbsenceDate状态。下面是一个查询的示例,它将完全相同(注意order by子句中的更改):

SELECT    
    lsm.EmployeeName,
    pd.absenceDate,
    pd.amountInDays * 8 AS [HoursReported],
    pd.status,
    (SUM(CASE WHEN pd.[status]='App' THEN (pd.amountInDays * 8)
              ELSE 0 END) OVER (partition by lsm.[EmployeeName] order by pd.absenceDate,
                                                                         case when pd.[status] = 'App' then 1 else 0 end)) AS [TotalUsedHours]
          ( @maxPSHours ) - (sum(
              CASE WHEN pd.[status]='App' THEN (pd.amountInDays * 8)
                   ELSE 0 END)
          over (
              partition by  lsm.[EmployeeName] order by pd.absenceDate,
                                                        case when pd.[status] = 'App' then 1 else 0 end)) AS [TotalRemainingHours]
FROM    
    [LocationStaffMembers] lsm 
INNER JOIN 
    [PersonalDays] pd ON lsm.staffMemberId = pd.staffMemberId
ORDER BY lsm.[EmployeeName],
         pd.absenceDate,
         case when pd.[status] = 'App' then 1 else 0 end