partition by - 如何正确使用以获取相关行

partition by - how to properly use in order to fetch related row

:)

我使用 postgresql 13,我确信我了解如何使用 PARTITION BY,但我想我错了。我创建了以下示例来说明我的问题。

我创建了这个 table:

id, group_id,order_id,text
1   1        1        a1
2   1        2        b1
3   2        1        a2
4   2        2        b2
5   3        1        a3

所以你有唯一的 ID,group_id,每组的顺序,还有一个文本。

我想 select 每行 order_id 1,所以我有每组的第一行,并且还获取每组最后 order_id 的文本.

所以我 运行 这个查询:

select id,group_id,order_id,the_text,
       last_value(the_text) over (partition by group_id order by order_id) last_text
from cdrs.my_test
where order_id=1;

它返回了

id,group_id,order_id,the_text,last_text
1,1,1,a1,a1
3,2,1,a2,a2
5,3,1,a3,a3

last_text和the_text是一样的,我选first_value()还是last_value()都无所谓。

last_text 列应该返回 b1、b2、a3。

我确信当我得到一行时,我可以使用 partition by 使用规则对该行进行分组,并从该组中的其他行获取数据。

我真的不明白为什么它不起作用。

如能提供有关此问题的任何信息,我们将不胜感激。

此致

杉木

demo:db<>fiddle

Window 函数在 WHERE 子句之后应用。因此,您无法获得最后一个值,因为您刚刚删除了它们。您可以使用子查询:

SELECT
    *
FROM (
    SELECT
        *,
        first_value(order_id) OVER (PARTITION BY group_id ORDER BY order_id),
        first_value(t) OVER (PARTITION BY group_id ORDER BY order_id DESC)
    FROM
    t
) s
WHERE order_id = 1

我会在这里使用 ROW_NUMBER 两次:

WITH cte AS (
    SELECT *,
        ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY order_id) rn_min,
        ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY order_id DESC) rn_max
    FROM cdrs.my_test
)

SELECT id, group_id, order_id, text
FROM cte
WHERE rn_min = 1 OR rn_max = 1
ORDER BY group_id, order_id;

留意the docs:

Note that first_value, last_value, and nth_value consider only the rows within the “window frame”, which by default contains the rows from the start of the partition through the last peer of the current row. This is likely to give unhelpful results for last_value and sometimes also nth_value. You can redefine the frame by adding a suitable frame specification (RANGE, ROWS or GROUPS) to the OVER clause. See Section 4.2.8 for more information about frame specifications.

因此您需要添加类似 rows between unbounded preceding and unbounded following 的内容,但随后您需要将过滤器移动到外部 select 否则它会在行被视为 [= 的一部分之前将其删除19=].

select * from (select id,group_id,order_id,the_text,
       last_value(the_text) over (partition by group_id order by order_id rows between current row and unbounded following) last_text
from my_test)foo where order_id=1;