[英]Using postgres window functions with different order by clause
我在 postgres window 函数中使用多个 order by 时遇到问题。 这是一个简短的例子。 Select 单个查询中的总行数,N 首行和 N 行末行。 (这不是我想要实现的任务,只是问题的一个例子)它是预期的行为还是 postgres 中的错误? 我正在使用 postgres 9.6
select generate_series(1, 10) id
into q;
select
count(*) over (),
lag(id , 0) over (order by id asc) a,
lag(id , 0) over (order by id desc) d
from q
limit 5;
Output:
10,10,10
10,9,9
10,8,8
10,7,7
10,6,6
预期的:
10,1,10
10,2,9
10,3,8
10,4,7
10,5,6
如果只选择了 N 个第一行或 N 个最后一行,则代码运行良好。
我曾经遇到过类似的问题,解释相同: https://stackoverflow.com/a/48668220/3984221
行为说明:
当您查看 EXPLAIN output 时,您可以解释这一点:
> | QUERY PLAN |
> | :--------------------------------------------------------------------------------------------------------------------------- |
> | WindowAgg (cost=368.69..445.19 rows=2550 width=20) (actual time=0.146..0.150 rows=10 loops=1) |
> | -> WindowAgg (cost=368.69..413.32 rows=2550 width=12) (actual time=0.128..0.136 rows=10 loops=1) |
> | -> Sort (cost=368.69..375.07 rows=2550 width=8) (actual time=0.126..0.128 rows=10 loops=1) |
> | Sort Key: id |
> | Sort Method: quicksort Memory: 25kB |
> | -> WindowAgg (cost=179.78..224.41 rows=2550 width=8) (actual time=0.048..0.056 rows=10 loops=1) |
> | -> Sort (cost=179.78..186.16 rows=2550 width=4) (actual time=0.033..0.034 rows=10 loops=1) |
> | Sort Key: id DESC |
> | Sort Method: quicksort Memory: 25kB |
> | -> Seq Scan on q (cost=0.00..35.50 rows=2550 width=4) (actual time=0.013..0.014 rows=10 loops=1) |
> | Planning Time: 0.292 ms |
> | Execution Time: 0.445 ms |
在这里你可以看到:首先有一个SORT Key: id DESC
。 所以一切都按DESC
顺序排列。 如果您只订购了DESC
function,这将是您的结果,正如您已经看到的。 现在,您有了第二个 window function。 因此,整个结果将再次排序,按ASC
顺序排列,包括。 你的第一个结果。 因此,您的第一个lag()
结果10, 9, 8, 7, 6, ...
将被重新排序为1, 2, 3, 4, 5, ...
然后将添加第二个lag()
结果。
但是,您的lag()
function 的具体结果当然是可以解释的:您不会转移数据,因此您会得到当前值。 当您将0
移位值变为1
时,您可以交叉检查这一点(就像我在上面的小提琴中所做的那样)。 然后您的DESC
lag()
将为id 1
返回2
,但ASC
给出NULL
。 一切安好。
因此,要创建您预期的 output,您需要另一种方法,例如使用row_number()
以ASC
和DESC
顺序添加行数,然后过滤它们:
SELECT
COUNT(*) OVER (),
a.id,
d.id
FROM (
select
id,
row_number() over (order by id asc)
from q
) a
JOIN (
select
id,
row_number() over (order by id desc)
from q
) d ON a.row_number = d.row_number
LIMIT 5
lag()
的第二个参数确定要回顾多少行。 所以lag(id, 0)
意味着回顾零行,这使得lag(id, 0)
相当于id
。 所以你得到的结果是完全理智的。
得到你想要的,你可以使用row_number()
加入。
SELECT count(*) OVER (),
x1.id,
x2.id
FROM (SELECT id,
row_number() OVER (ORDER BY id ASC) r
FROM q) x1
INNER JOIN (SELECT id,
row_number() OVER (ORDER BY id DESC) r
FROM q) x2
ON x2.r = x1.r
ORDER BY x1.r
LIMIT 5;
来自 over 子句之一的顺序应用于数据。 但数据只排序一次。 通过以下查询可以实现所需的行为。
select count(*) over (),
(array_agg(id) over (order by id asc rows between unbounded preceding and unbounded following))[row_number() over ()] a,
(array_agg(id) over (order by id desc rows between unbounded preceding and unbounded following))[row_number() over ()] d
from q
order by id
limit 5
可能 memory 对大表无效,因为 array_agg 从所有行构造数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.