[英]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.