我有一个PostgreSQL表包含:person_identifier,period_identifier,status
person | period | status
-------+--------+--------
Bob | Jan | new
Bob | Feb | retained
Bob | Mar | retained
Bob | Apr | dormant
Bob | May | dormant
Bob | Jun | resurected
Bob | Jul | retained
Bob | Agu | dormant
Jim | Jan | new
Jim | Feb | dormant
Jim | Mar | dormant
Jim | Apr | dormant
Jim | May | dormant
Jim | Jun | resurected
Jim | Jul | dormant
Jim | Agu | resurected
我需要的是包括counter
的person, status
分组,其限制是只要状态改变,计数器就需要重新启动到1。
我尝试了以下查询,但只要状态发生变化,这就不会将计数器降低到1:
reset
这是我的查询与实际需要的区别; SELECT
*,
ROW_NUMBER() OVER (PARTITION BY person, status ORDER BY period) AS wrong_counter
FROM
my_table
:
* stands for wrong value
谁能帮我这个?
我做了一些规范化:
person | period | status | wrong_counter | needed_counter
-------+--------+-------------+ --------------+---------------
Bob | Jan | new | 1 | 1
Bob | Feb | retained | 1 | 1
Bob | Mar | retained | 2 | 2
Bob | Apr | dormant | 1 | 1
Bob | May | dormant | 2 | 2
Bob | Jun | resurected | 1 | 1
Bob | Jul | retained | 3* | 1
Bob | Agu | dormant | 3* | 1
Jim | Jan | new | 1 | 1
Jim | Feb | dormant | 1 | 1
Jim | Mar | dormant | 2 | 2
Jim | Apr | dormant | 3 | 3
Jim | May | dormant | 4 | 4
Jim | Jun | resurected | 1 | 1
Jim | Jul | dormant | 5* | 1
Jim | Agu | resurected | 2* | 1
并用作basetable:public.tbl_test
然后我做一些计算:首先获取实际行之前的行中的状态,是否为status_change。创建一个help_partition,然后在help_partition上获取row_number。
person -> person_fk,
period -> period_int, Jan = 1 ...
status -> status_fk
并导致:(最后一行是你需要的计数器)
with temp_base_data as
(
select
*,
lag(status_fk,1,-1) over(ORDER BY person_fk, period_int) as status_before,
case
when lag(status_fk,1,-1) over(ORDER BY person_fk, period_int) = status_fk and lag(person_fk ,1,-1) over(ORDER BY person_fk, period_int) = person_fk
then 0
else 1
end as status_change
from public.tbl_test
order by person_fk, period_int
),
temp_partition AS
(
select
*,
sum(status_change) over ( order by person_fk, period_int RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as help_partition
from temp_base_data
order by person_fk, period_int
)
select
* ,
row_number() over (PARTITION by help_partition order by person_fk, period_int) as counter
from temp_partition
order by id