last_value() 窗口函数到底做了什么?

And*_*mar 6 sql-server window-functions

在测试我对SQL 的回答- 从每个组的第一行和最后一行获取数据时,我注意到一些奇怪的事情。在first_valuelast_value窗口功能,出现不同的表现。

正如预期的那样,从具有最小值的行中first_value(col1) over (order by col2)找到 的值。但似乎找到了当前行的值。 似乎与其操作的组或分区无关。col1col2last_value(col1) over (order by col2)last_value

对于下面的查询:

id  Session ID  bal
0   00000002    100
1   00000002    120
2   00000002    140
3   00000001    900
4   00000001    800
5   00000001    500
Run Code Online (Sandbox Code Playgroud)

表达方式:

last_value(bal) over (partition by [Session ID] order by id) as lv
Run Code Online (Sandbox Code Playgroud)

返回与以下内容不同的内容:

first_value(bal) over (partition by [Session ID] order by id DESC) as fv_desc
Run Code Online (Sandbox Code Playgroud)

结果如下(注意lv一组内的值变化):

lv       fv_desc
500      500
800      500
900      500
140      140
120      140
100      140
Run Code Online (Sandbox Code Playgroud)

带有一些额外列的 SQL Fiddle 示例。 反转order by或省略partition by似乎不会影响last_value()返回的内容。

如果我正确阅读了MSDN 页面,它表明last_value()应该与 相反first_value(),这与我在测试期间观察到的不同。

不会last_value()做它应该做的?为什么当它似乎不使用时last_value()允许您指定partition和/或order by子句?

Jam*_*s Z 8

发生这种情况是因为默认窗口框架是range between unbounded preceding and current row,因此last_value()除非您更改框架,否则永远不会超出当前行。

来自 MSDN:

如果未指定 ORDER BY,则整个分区用于窗口框架。这仅适用于不需要 ORDER BY 子句的函数。如果未指定 ROWS/RANGE 但指定了 ORDER BY,则 RANGE UNBOUNDED PRECEDING AND CURRENT ROW 用作窗口框架的默认值。这仅适用于可以接受可选的 ROWS/RANGE 规范的函数。例如,排序函数不能接受 ROWS/RANGE,因此即使 ORDER BY 存在而 ROWS/RANGE 不存在,也不应用此窗口框架。

由于last_value()有一个可选的order by子句,它的默认窗口框架在当前行结束。因此,对于默认框架,无论您选择哪个分区或排序,都last_value()将返回当前行的值。