簡體   English   中英

使用具有不同 order by 子句的 postgres window 函數

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


行為說明:

演示:db<>小提琴

當您查看 EXPLAIN output 時,您可以解釋這一點:

> | QUERY PLAN                                                                                                                   |
> | :--------------------------------------------------------------------------------------------------------------------------- |
> | WindowAgg  (cost=368.69..445.19 rows=2550 width=20) (actual time=0.146..0.150 rows=10 loops=1)                               |
> |   -&gt;  WindowAgg  (cost=368.69..413.32 rows=2550 width=12) (actual time=0.128..0.136 rows=10 loops=1)                         |
> |         -&gt;  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                                                                           |
> |               -&gt;  WindowAgg  (cost=179.78..224.41 rows=2550 width=8) (actual time=0.048..0.056 rows=10 loops=1)              |
> |                     -&gt;  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                                                               |
> |                           -&gt;  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()ASCDESC順序添加行數,然后過濾它們:

演示:db<>小提琴

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM