我正在使用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
答案 0 :(得分:1)
您正在执行累积总和,根据AbsenceDate
(sum(...) over (partition by ... order by pd.absenceDate
)的顺序返回结果。但是你的最后2条记录的日期完全相同(11/20/2015
) - 至少,根据你向我们展示的内容。这造成了歧义。
因此,在计算累积总和时,SQL Server正在 如果2行确实共享完全相同的日期,那么您必须找到第2列以消除歧义并将其添加到累积 或者,当2 approved hours
行处理2 declined hours
行之前是完全可以想象的,也是合法的 - 这将解释您当前的结果 - 尽管行本身以不同的顺序返回给您(顺便说一句,考虑在查询中添加order by
子句,否则,行本身的顺序无法保证)。 / p>
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