在 PostgreSQL 中根据多个字段更改(包括 "invisible" 一个)对行进行编号

Numbering rows based on multiple fields changes (incluging an "invisible" one) in PostgreSQL

之前的题目我看了看,还是达不到我想要的

我有一个这样的 table :

id   status     update_date
---  ---        ---
A    PENDING    2020-11-01
A    PENDING    2020-11-02
A    CONFIRMED  2020-11-03
A    CONFIRMED  2020-11-04
A    CONFIRMED  2020-11-05
A    PENDING    2020-11-06
A    PAID       2020-11-07
B    CONFIRMED  2020-11-02
etc.

我想要这个:

id   status     rank
---  ---        ---
A    PENDING    1
A    CONFIRMED  2
A    PENDING    3
A    PAID       4
B    CONFIRMED  1
etc.

意味着考虑 update_date(当然还有状态变化)对行进行排序和编号,但最终结果中没有订单日期

PS:如您所见,我可以多次从一种状态来回切换到另一种状态(PENDING -> CONFIRMED -> PENDING -> 等)

非常感谢!

您可以将此作为间隙和孤岛问题来解决。行号之间的差异为您提供了每条记录所属的组,然后您可以使用它来聚合:

select id, status, 
    row_number() over(partition by id order by min(update_date)) as rn
from (
    select t.*,
        row_number() over(partition by id order by update_date) rn1,
        row_number() over(partition by id, status order by update_date) rn2
    from mytable t
) t
group by id, status, rn1 - rn2
order by id, min(update_date) 

Demo on DB Fiddle:

id | status    | rn
:- | :-------- | -:
A  | PENDING   |  1
A  | CONFIRMED |  2
A  | PENDING   |  3
A  | PAID      |  4
B  | CONFIRMED |  1

step-by-step demo:db<>fiddle

SELECT
    id, 
    status,
    row_number() OVER (PARTITION BY id)                                      -- 3
FROM (
    SELECT
        *,
        lead(status) OVER (PARTITION BY id ORDER BY update_date) AS next     -- 1
    FROM
        mytable
) s
WHERE status != next OR next is null                                         -- 2
  1. lead() window function 将下一个 status 值复制到当前记录
  2. 删除所有记录,其中当前和下一个 status 相等(状态无变化)
  3. 使用 row_number() window 函数添加行计数