我在SQL Server 2012中有一个表,如快照所示:
然后我使用Last_Value()和First Value来获取不同YearMonth的每个EmpID的AverageAmount。脚本如下:
SELECT A.EmpID,
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '200901AvgAmount',
Last_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '201112AvgAmount'
FROM Emp_Amt AS A
但是,此查询的结果是:
在“201112AvgAmount”列中,它显示每个EmpID的不同值,而“200901AvgAmount”具有正确的值。
我的SQL脚本有什么问题吗?我在网上做了很多研究,但仍然找不到答案......
答案 0 :(得分:16)
这是一个快速查询来说明行为:
select
v,
-- FIRST_VALUE() and LAST_VALUE()
first_value(v) over(order by v) f1,
first_value(v) over(order by v rows between unbounded preceding and current row) f2,
first_value(v) over(order by v rows between unbounded preceding and unbounded following) f3,
last_value (v) over(order by v) l1,
last_value (v) over(order by v rows between unbounded preceding and current row) l2,
last_value (v) over(order by v rows between unbounded preceding and unbounded following) l3,
-- For completeness' sake, let's also compare the above with MAX()
max (v) over() m1,
max (v) over(order by v) m2,
max (v) over(order by v rows between unbounded preceding and current row) m3,
max (v) over(order by v rows between unbounded preceding and unbounded following) m4
from (values(1),(2),(3),(4)) t(v)
上面的查询输出可以在这里看到(SQLFiddle here):
| V | F1 | F2 | F3 | L1 | L2 | L3 | M1 | M2 | M3 | M4 |
|---|----|----|----|----|----|----|----|----|----|----|
| 1 | 1 | 1 | 1 | 1 | 1 | 4 | 4 | 1 | 1 | 4 |
| 2 | 1 | 1 | 1 | 2 | 2 | 4 | 4 | 2 | 2 | 4 |
| 3 | 1 | 1 | 1 | 3 | 3 | 4 | 4 | 3 | 3 | 4 |
| 4 | 1 | 1 | 1 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
很少有人会想到应用于采用ORDER BY
子句的窗口函数的隐式框架。在这种情况下,窗口默认为框架RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
。 (RANGE与ROWS并不完全相同,但这是另一个故事)。以这种方式思考:
v = 1
的行上,有序窗口的框架跨度为v IN (1)
v = 2
的行上,有序窗口的框架跨度为v IN (1, 2)
v = 3
的行上,有序窗口的框架跨度为v IN (1, 2, 3)
v = 4
的行上,有序窗口的框架跨度为v IN (1, 2, 3, 4)
如果您想阻止这种行为,您有两种选择:
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
子句
ORDER BY
子句(如MAX(v) OVER()
)更详细信息在this article about LEAD()
, LAG()
, FIRST_VALUE()
and LAST_VALUE()
答案 1 :(得分:11)
您的脚本没有任何问题,这是SQL Server中分区的工作方式:/。如果将LAST_VALUE更改为MAX,结果将是相同的。解决方案是:
SELECT A.EmpID,
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '200901AvgAmount',
Last_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS '201112AvgAmount'
FROM Emp_Amt AS A
有一篇很棒的帖子,link。 GL!
答案 2 :(得分:0)
最简单的方法是使用first_value重复查询,只需将顺序作为第一种情况的asc和第二种情况的desc。
SELECT A.EmpID,
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '200901AvgAmount',
First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey desc) AS '201112AvgAmount'
FROM Emp_Amt AS A