I have a table with following data:
Action Code Place Date Remove A Place 1 2019-03-15 Install A Place 2 2019-10-01 Remove A Place 2 2022-07-12 Install A Place 3 2023-01-01
There are two actions possible. ‘Remove’ and ‘Install’. How can I find Place for Code A for given date? For example for 2015 it will be Place 1. For 2020 it will be Place 2. For 2025 it will be Place 3.
I think the first and the most difficult step is to transform it to table that contains start and end date. Then I can use between function.
Example output:
A Place StartDate EndDate A Place 1 1900-01-01 2019-03-15 -- we dont have start date so we can use for ex. 1900 A Place 2 2019-10-01 2022-07-12 A Place 3 2023-01-01 3000-01-01 -- we dont have end date so we can use for ex. 3000
I have tried with LEAD/LAG but we have two different actions here so I think it is not the best idea. How could I deal with this problem?
Thanks.
Advertisement
Answer
I understand. The following uses union all
to be sure it gets all values.
select code, place, '1900-01-01' as startdate, date as enddate from (select t.*, row_number() over (partition by code order by date) as seqnum from t ) t where seqnum = 1 and action = 'Remove' union all select code, place, date as startdate, enddate from (select t.*, lead(date, 1, '3000-01-01') over (partition by code order by date) as enddate from t ) t where action = 'Install';
The first subquery handles the case where the data starts with 'Remove'
. The second takes all 'installs'
and sets up the date to the next record.
Note that this will work even if the places are interleaved in the data (so a code returns to a place after some period of time).
Here is a db<>fiddle.