这是我的数据(请注意,这只是一个实体ID /员工ID,将有多个。一个实体ID下可以有多个员工ID):
SELECT EntityId,
EmployeeId,
PayPeriodStart,
IsFullTime
FROM dbo.Payroll
WHERE EmployeeId = 316691
AND PayPeriodStart <= '12/31/2014'
AND PayPeriodEnd >= '1/1/2014';
我想获取每个EntityID&amp;的最后“IsFullTime”值。 EmployeeID组合。
我试过这样做:
SELECT EntityId,
EmployeeId,
LAST_VALUE(IsFullTime) OVER (PARTITION BY EntityId, EmployeeId ORDER BY EntityId, EmployeeId, PayPeriodStart) AS LastIsFullTimeValue
FROM dbo.Payroll
WHERE EmployeeId = 316691
AND PayPeriodStart <= '12/31/2014'
AND PayPeriodEnd >= '1/1/2014';
但我得到了这个:
查询应该只返回一行FOR EACH EntityID / EmployeeID。
我做错了什么?
答案 0 :(得分:12)
尝试添加ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
我认为包含ORDER BY
的分析函数的默认窗口在当前行结束。
LAST_VALUE(IsFullTime) OVER (
PARTITION BY EntityId, EmployeeId
ORDER BY EntityId, EmployeeId, PayPeriodStart
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS LastIsFullTimeValue
答案 1 :(得分:5)
这就是诀窍。我使用FIRST_VALUE
+ DESC
排序(而不是LAST_VALUE
+ ASC
排序)。作品。这是最短的方式,可以让你避免可怕的 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
。
FIRST_VALUE(IsFullTime) OVER (
PARTITION BY EntityId, EmployeeId
ORDER BY EntityId DESC, EmployeeId DESC, PayPeriodStart DESC
) AS LastIsFullTimeValue
同意,令人困惑的是,为什么LAST_VALUE
不直观,与其孪生姐妹FIRST_VALUE
相比需要如此多的关注。
答案 2 :(得分:2)
我相信您希望使用ROW_NUMBER()
并根据payperiodstart
日期获取最后一个值:
SELECT t.EntityId
,t.EmployeeId
,t.LastIsFullTimeValue
FROM (
SELECT EntityId
,EmployeeId
,ROW_NUMBER() OVER (
PARTITION BY EntityId
,EmployeeId ORDER BY PayPeriodStart DESC
) AS rn
,LastIsFullTimeValue
FROM dbo.Payroll
WHERE EmployeeId = 316691 -- you could probably put this in your outer query instead
AND PayPeriodStart <= '12/31/2014'
AND PayPeriodEnd >= '1/1/2014'
) t
WHERE t.rn = 1;
答案 3 :(得分:0)
要查看正在发生的情况,您必须了解框架的概念。该框架允许您为窗口指定一组行,该行甚至比分区小。默认框架包含从第一行到当前行的所有行。对于第1行,该窗口仅是第1行。对于第3行,该窗口包含第1至3行。使用FIRST_VALUE时,默认情况下包括第一行,因此您不必担心会获得预期的结果
将LAST_VALUE与默认框架一起使用时,该窗口仅上升到当前行。当前行是窗口的最后一行。要变通解决此问题,您必须指定框架,在这种情况下行在当前行和未绑定跟随之间行。这意味着窗口从当前行开始,并在分区的最后一行结束。运行下一个示例,看看如何正确使用LAST_VALUE。