Reputation: 19628
I have a fact table which stores the historical status at an individual level, in a format similar to this:
---------------------------
| person | year | state |
---------------------------
| P1 | 2001 | S1 |
| P1 | 2002 | S1 |
| P1 | 2003 | S2 |
...
| PN | ... | SX |
--------------------------
And I am trying to calcuate the "transition" between consecutive years within each individual, the expected output will be
-------------------------------------
| person | year | state | year | state |
-------------------------------------
| P1 | 2001 | S1 | 2002 | S1
| P1 | 2002 | S1 | 2003 | S2
| P1 | 2003 | S2 | 2004 | ..
...
| PN | ... | SX | ... | ..
-------------------------------------
I was planning joining the table with itself like below, however, the table is big and this feel like a full cartesian join. I am wondering if there is a more efficient way like window function or similar that can be more efficient and elegant.
select
t1.person,
t1.year,
t1.state,
t2.year as year_next,
t2.state as state_next
from table t1
inner join table t2
on t1.person = t2.person
and t1.year + 1 = t2.year;
Thoughts?
Upvotes: 1
Views: 335
Reputation: 164099
You can do it with LEAD() window function.
If there are no gaps between the years:
select *,
lead(year) over (partition by person order by year) next_year,
lead(state) over (partition by person order by year) next_state
from tablename
order by person, year
If there are gaps between the years:
select person, year, state,
case when next_year = year + 1 then next_year end next_year,
case when next_year = year + 1 then next_state end next_state
from (
select *,
lead(year) over (partition by person order by year) next_year,
lead(state) over (partition by person order by year) next_state
from tablename
) t
order by person, year
Upvotes: 1