Reputation: 23
I have the following problem:
I have a table containing two types of data. One with state = 1 and one with state = 2. For every row with state = 2 I need the last corresponding date with state = 1. Here's an example:
date state id
'2016-04-03' 1 1
'2016-04-04' 1 1
'2016-04-05' 2 1
'2016-04-06' 2 1
Expected result:
date lastdate state id
'2016-04-03' '2016-04-03' 1 1
'2016-04-04' '2016-04-04' 1 1
'2016-04-05' '2016-04-04' 2 1
'2016-04-06' '2016-04-04' 2 1
'2016-04-07' '2016-04-07' 1 1
I don't exactly know where I am stuck. It feels like this problems you're looking at the wrong way so any help is appreciated.
Thx in advance!
Edit
As it seems like I didn't explain my problem good enough, here's another try:
For every row I need the date of the last row with the same id which had state = 1. If the state is already 1 the date of the same row is needed.
So to clarify my "expected results" - Table:
date lastdate state id
'2016-04-03' '2016-04-03' 1 1
state is 1 so date of row is last date with state 1
'2016-04-04' '2016-04-04' 1 1
state is 1 so date of row is last date with state 1
'2016-04-05' '2016-04-04' 2 1
state is 2 so date of the last row with date 1 is from the row before
'2016-04-06' '2016-04-04' 2 1
state is 2, last date with state = 1 is '2016-04-04'
'2016-04-07' '2016-04-07' 1 1
state is 1 again, so same date
'2016-04-08' '2016-04-07' 2 1
state is 2, so date of last row (row before) is set
I hope my intentions are understandable now.
Upvotes: 2
Views: 1288
Reputation: 121534
This can be accomplished by joining a table with itself:
select distinct on (a.date)
a.date date,
coalesce(b.date, a.date) last_date,
a.state,
a.id
from test a
left join test b
on a.state = 2 and b.state = 1 and b.date < a.date
order by a.date, b.date desc;
date | last_date | state | id
------------+------------+-------+----
2016-04-03 | 2016-04-03 | 1 | 1
2016-04-04 | 2016-04-04 | 1 | 1
2016-04-05 | 2016-04-04 | 2 | 1
2016-04-06 | 2016-04-04 | 2 | 1
2016-04-07 | 2016-04-07 | 1 | 1
(5 rows)
Upvotes: 1
Reputation: 1058
Here is my solution
select t1.date as date, (
select date
from mytable where state = 1 and t1.date::date - date::date >= 0 order by t1.date::date - date::date limit 1
) as last_date
,t1.state , t1.id from mytable t1 where state = 2
Upvotes: 0
Reputation: 114
I would suggest something like this (I'm not sure everything in the syntax is correct):
CREATE OR REPLACE FUNCTION dates() RETURNS TABLE (date DATE, lastdate DATE,
state INTEGER, id INTEGER) AS $$
DECLARE
lastType1 DATE;
BEGIN
FOR d IN (SELECT * FROM tableName)
LOOP
IF d.state == 1 THEN
lastType1 = d.date;
END IF;
RETURN NEXT (d.date, lastType1, d.state, d.id);
END LOOP;
RETURN;
END
LANGUAGE 'plpgsql';
This you can call by SELECT * FROM dates()
, if you want to access it like a table i would recommend creating a view calling the function
You just have to put instead of dates()
what you want to call your function and instead of tableName
what you table is actually called
Upvotes: 0