I have a table:
id | date | value |
---|---|---|
1 | 2022-01-01 | 1 |
1 | 2022-01-02 | 1 |
1 | 2022-01-03 | 2 |
1 | 2022-01-04 | 2 |
1 | 2022-01-05 | 3 |
1 | 2022-01-06 | 3 |
I want to detect changing of value column by date:
id | date | value | diff |
---|---|---|---|
1 | 2022-01-01 | 1 | null |
1 | 2022-01-02 | 1 | null |
1 | 2022-01-03 | 2 | 1 |
1 | 2022-01-04 | 2 | 1 |
1 | 2022-01-05 | 3 | 2 |
1 | 2022-01-06 | 3 | 2 |
I tried a window function lag(), but all I got:
id | date | value | diff |
---|---|---|---|
1 | 2022-01-01 | 1 | null |
1 | 2022-01-02 | 1 | 1 |
1 | 2022-01-03 | 2 | 1 |
1 | 2022-01-04 | 2 | 2 |
1 | 2022-01-05 | 3 | 2 |
1 | 2022-01-06 | 3 | 3 |
I am pretty sure you have to do a gaps-and-islands to "group" your changes.
There may be a more concise way to get the result you want, but this is how I would solve this:
with changes as ( -- mark the changes and lag values
select id, date, value,
coalesce((value != lag(value) over w)::int, 1) as changed_flag,
lag(value) over w as last_value
from a_table
window w as (partition by id order by date)
), groupnums as ( -- number the groups, carrying the lag values forward
select id, date, value,
sum(changed_flag) over (partition by id order by date) as group_num,
last_value
from changes
window w as (partition by id order by date)
) -- final query that uses group numbering to return the correct lag value
select id, date, value,
first_value(last_value) over (partition by id, group_num
order by date) as diff
from groupnums;
db<>fiddle here
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.