样本数据
CREATE TABLE test
(id integer, session_ID integer, value integer)
;
INSERT INTO test
(id, session_ID, value)
VALUES
(0, 2, 100),
(1, 2, 120),
(2, 2, 140),
(3, 1, 900),
(4, 1, 800),
(5, 1, 500)
;
当前查询
select
id,
last_value(value) over (partition by session_ID order by id) as last_value_window,
last_value(value) over (partition by session_ID order by id desc) as last_value_window_desc
from test
ORDER BY id
我遇到了last_value()
窗口函数的问题:http://sqlfiddle.com/#!15/bcec0/2
在last_value()
查询中,我尝试使用排序方向。
编辑:问题不是:为什么我没有得到所有时间的最后一个值,以及如何使用frame子句(unbounded preceding
和unbounded following
)。我知道first_value(desc)
和last_value()
的区别,以及last_value()
没有给出所有时间的最后值的问题:
默认框架子句在当前行之前是无界的。因此,第一个值总是给出第一行的子句。因此,如果只有一行( frame子句只包含这个行)或一个hundered ( frame子句包含所有的100),这并不重要。结果总是第一个。在DESC顺序中,它是相同的: DESC更改排序顺序,然后第一行是最后一个值,不管您得到多少行。
对于last_value()
,这种行为非常相似:如果您有一行,它将为您提供默认框架子句的最后一个值:这个一行。在第二行,frame子句包含这两行,最后一行是第二行。这就是为什么last_value()
不为您提供所有行的最后一行,而只给出在当前行之前的最后一行。
但是,如果我将顺序更改为DESC,我希望我有第一行中的最后一行,所以我在第一行得到了这一行,而在第二行得到了最后一行但第二行,以此类推。但这不是结果。为什么?
对于当前的示例,这些是first_value()
、first_value(desc)
、last_value()
、last_value(desc)
的结果,以及我对last_value(desc)
的期望。
id | fv_asc | fv_desc | lv_asc | lv_desc | lv_desc(expecting)
----+--------+---------+--------+---------+--------------------
0 | 100 | 140 | 100 | 100 | 140
1 | 100 | 140 | 120 | 120 | 120
2 | 100 | 140 | 140 | 140 | 100
3 | 900 | 500 | 900 | 900 | 500
4 | 900 | 500 | 800 | 800 | 800
5 | 900 | 500 | 500 | 500 | 900
对我来说,ORDER BY DESC
标志似乎在默认框架子句last_value()
调用中被忽略了。但这并不属于first_value()
的范围。所以我的问题是:为什么last_value()
结果与last_value(desc)
相同?
发布于 2018-02-07 08:03:52
一年后,我找到了解决办法:
请接受以下陈述:
SELECT
id,
array_accum(value) over (partition BY session_ID ORDER BY id) AS window_asc,
first_value(value) over (partition BY session_ID ORDER BY id) AS first_value_window_asc,
last_value(value) over (partition BY session_ID ORDER BY id) AS last_value_window_asc,
array_accum(value) over (partition BY session_ID ORDER BY id DESC) AS window_desc,
first_value(value) over (partition BY session_ID ORDER BY id DESC) AS first_value_window_desc,
last_value(value) over (partition BY session_ID ORDER BY id DESC) AS last_value_window_desc
FROM
test
ORDER BY
id
这给了我们
id window_asc first_value_window_asc last_value_window_asc window_desc first_value_window_desc last_value_window_desc
-- ------------- ---------------------- --------------------- ------------- ----------------------- ----------------------
0 {100} 100 100 {140,120,100} 140 100
1 {100,120} 100 120 {140,120} 140 120
2 {100,120,140} 100 140 {140} 140 140
3 {900} 900 900 {500,800,900} 500 900
4 {900,800} 900 800 {500,800} 500 800
5 {900,800,500} 900 500 {500} 500 500
array_accum
显示使用的窗口。在那里,您可以看到窗口的第一个和当前的最后一个值。
所发生的事情显示了执行计划:
"Sort (cost=444.23..449.08 rows=1940 width=12)"
" Sort Key: id"
" -> WindowAgg (cost=289.78..338.28 rows=1940 width=12)"
" -> Sort (cost=289.78..294.63 rows=1940 width=12)"
" Sort Key: session_id, id"
" -> WindowAgg (cost=135.34..183.84 rows=1940 width=12)"
" -> Sort (cost=135.34..140.19 rows=1940 width=12)"
" Sort Key: session_id, id"
" -> Seq Scan on test (cost=0.00..29.40 rows=1940 width=12)"
在这里您可以看到:首先,前三个窗口函数有一个ORDER BY id
。
这使(如所述)
id window_asc first_value_window_asc last_value_window_asc
-- ------------- ---------------------- ---------------------
3 {900} 900 900
4 {900,800} 900 800
5 {900,800,500} 900 500
0 {100} 100 100
1 {100,120} 100 120
2 {100,120,140} 100 140
然后,您可以看到另一种类型:下面三个窗口函数的ORDER BY id DESC
。这种类型给出:
id window_asc first_value_window_asc last_value_window_asc
-- ------------- ---------------------- ---------------------
5 {900,800,500} 900 500
4 {900,800} 900 800
3 {900} 900 900
2 {100,120,140} 100 140
1 {100,120} 100 120
0 {100} 100 100
通过这种排序,将执行DESC
窗口函数。array_accum
列显示结果窗口:
id window_desc
-- -------------
5 {500}
4 {500,800}
3 {500,800,900}
2 {140}
1 {140,120}
0 {140,120,100}
生成的(first_value DESC
和) last_value DESC
现在与last_value ASC
完全相同
id window_asc last_value_window_asc window_desc last_value_window_desc
-- ------------- --------------------- ------------- ----------------------
5 {900,800,500} 500 {500} 500
4 {900,800} 800 {500,800} 800
3 {900} 900 {500,800,900} 900
2 {100,120,140} 140 {140} 140
1 {100,120} 120 {140,120} 120
0 {100} 100 {140,120,100} 100
现在我明白了为什么last_value ASC
等于last_value DESC
。这是因为窗口的第二个ORDER
函数给出了一个倒窗口。
(执行计划的最后一个类型是语句的最后一个ORDER BY
。)
作为一点好处:这个查询显示出一些优化潜力:如果首先调用DESC
窗口,然后调用ASC
窗口,则不需要第三种类型。在这个时刻,它是正确的。
发布于 2017-02-17 05:33:42
LAST_VALUE()
的问题在于,窗口子句的默认规则删除了您真正想要的值。这是一个非常微妙的问题,在所有支持此功能的数据库中都是如此。
这来自甲骨文博客:
当我们讨论窗口子句时,第一个函数和最后一个函数的隐式和不可更改的窗口子句是在无界的前面和无界跟随之间的行,换句话说,是分区中的所有行。对于FIRST_VALUE和LAST_VALUE,默认但可变的窗口子句是无界的前一行和当前行之间的行,换句话说,我们排除当前行之后的行。当我们寻找列表中的第一行( FIRST_VALUE )时,从列表底部删除行没有什么区别,但当我们查找列表( LAST_VALUE ) 中的最后一行时,这确实会产生影响,因此,在使用LAST_VALUE时,通常需要在无界的前面和无界的后续之间指定行,或者只使用FIRST_VALUE并反转排序顺序。
因此,只需使用FIRST_VALUE()
。这做你想做的事:
with test (id, session_ID, value) as (
(VALUES (0, 2, 100),
(1, 2, 120),
(2, 2, 140),
(3, 1, 900),
(4, 1, 800),
(5, 1, 500)
)
)
select id,
first_value(value) over (partition by session_ID order by id) as first_value_window,
first_value(value) over (partition by session_ID order by id desc) as first_value_window_desc
from test
order by id
发布于 2017-02-17 07:06:35
检查窗口框是如何定义的。这个例子可能会有所帮助:
select
id,
last_value(value) over (
partition by session_id
order by id
) as lv_asc,
last_value(value) over (
partition by session_id
order by id desc
) as lv_desc,
last_value(value) over (
partition by session_id
order by id
rows between unbounded preceding and unbounded following
) as lv_asc_unbounded,
last_value(value) over (
partition by session_id
order by id desc
rows between unbounded preceding and unbounded following
) as lv_desc_unbounded
from t
order by id;
id | lv_asc | lv_desc | lv_asc_unbounded | lv_desc_unbounded
----+--------+---------+------------------+-------------------
0 | 100 | 100 | 140 | 100
1 | 120 | 120 | 140 | 100
2 | 140 | 140 | 140 | 100
3 | 900 | 900 | 500 | 900
4 | 800 | 800 | 500 | 900
5 | 500 | 500 | 500 | 900
https://stackoverflow.com/questions/42299101
复制