Reputation: 1449
Given a data set for example as follows:
PERSON - the person allocating funds (key field)
EFFECTIVE DATE - the effective date of the percentage distribution
RECIPIENT - the person receiving a certain percentage of the funds
PERCENTAGE - the percentage that the person receives
(so for any given effective date, a person allocates a total of 100% to any given combination of recipients)
PERSON EFFECTIVE DATE RECIPIENT PERCENTAGE
---------- --------------- ------------- -----------
MONICA 2015-10-01 BARNEY 100% +
MONICA 2015-09-01 BARNEY 50% +
MONICA 2015-09-01 MARSHALL 20% +
MONICA 2015-09-01 LILY 30% +
MONICA 2015-08-01 ROBIN 50%
MONICA 2015-08-01 TED 50%
CHANDLER 2015-10-01 ROBIN 50% +
CHANDLER 2015-10-01 LILY 50% +
CHANDLER 2015-07-10 BARNEY 50% +
CHANDLER 2015-07-10 MARSHALL 50% +
CHANDLER 2015-06-01 ROBIN 50%
CHANDLER 2015-06-01 LILY 50%
CHANDLER 2015-04-10 BARNEY 50%
CHANDLER 2015-04-10 MARSHALL 50%
ROSS 2015-10-01 MARSHALL 100% +
ROSS 2015-09-15 BARNEY 100% +
PHOEBE 2015-10-01 MARSHALL 20% +
PHOEBE 2015-10-01 BARNEY 20% +
PHOEBE 2015-10-01 LILY 20% +
PHOEBE 2015-10-01 ROBIN 20% +
PHOEBE 2015-10-01 TED 20% +
PHOEBE 2015-09-01 MARSHALL 100% +
PHOEBE 2015-08-01 BARNEY 100%
PHOEBE 2015-07-01 LILY 100%
PHOEBE 2015-06-01 ROBIN 100%
PHOEBE 2015-05-01 TED 100%
How can I construct a single SQL query that would return only the two latest sets of allocations per person at once (all of the records marked with a "+" above)? This is so that I could process the data into a display that says, for example, that:
"Monica changed allocation FROM 50% for Barney, 20% for Marshall, and 30% for Lily TO 100% for Barney."
"Chandler changed allocation FROM 50% for Barney, 50% for Marshall TO 50% for Robin, 50% for Lily."
"Ross changed allocation FROM 100% for Barney TO 100% for Marshall."
"Phoebe changed allocation FROM 100% for Marshall TO 20% for Marshall, 20% for Lily, 20% for Barney, 20% for Robin, 20% for Ted."
Upvotes: 0
Views: 81
Reputation: 21
row_number is another option
select t.*
from (select t.*,
row_number() over (partition by person order by effective_date desc) as seqnum
from t
) t
where seqnum <= 2;
Upvotes: 0
Reputation: 1066
Can try like this.
select *
from table as W
where w.effective_date >= (
//get 2nd max effective date
select max(a.effective_date) from table as a
where a.person = w.person
and a.effective_date Not = (
//get max of effective_date per person
select max(x.effective_date) from table as x
where x.person = a.person)
)
Upvotes: 0
Reputation: 1269643
Here is one method using where
:
select t.*
from t
where t.effective_date in (select t2.effective_date
from t t2
where t2.person = t.person
group by t2.effective_date
order by t2.effective_date desc
fetch first 2 rows only
);
You can also do this with dense_rank()
:
select t.*
from (select t.*,
dense_rank() over (partition by person order by effective_date desc) as seqnum
from t
) t
where seqnum <= 2;
Upvotes: 1