Reputation: 1039
Blockquote
Given these requirements:
rate lookup table:
effective_start_date | effective_end_date | amount | rate_type
----------------------------------------------------------------
2016-01-16 00:00:00 | 2016-02-15 00:00:00 | 0.10 | rate1
2016-01-16 00:00:00 | 2016-02-15 00:00:00 | 156 | rate2 (annual)
2016-02-16 00:00:00 | 2016-03-15 00:00:00 | 0.15 | rate1
input/source table:
datetime | person | qty | x | vatable
-------------------------------------------------
2016-01-15 00:00:00 | p1 | 10 | x1 | Y
2016-01-16 00:00:00 | p1 | 10 | x1 | Y
2016-01-16 00:00:00 | p1 | 11 | x2 | N
2016-01-16 01:00:00 | p1 | 9 | x1 | Y
2016-01-16 02:00:00 | p2 | 10 | x1 | Y
2016-02-15 00:00:00 | p1 | 8 | x1 | Y
2016-02-15 00:00:00 | p1 | 8 | x2 | Y
2016-02-16 00:00:00 | p1 | 8 | x1 | Y
2016-02-16 00:00:00 | p1 | 7 | x2 | Y
if rate2 is used:
monthly_qty = sum of qty PER month of param (jan 16 - 31, feb 1 - 15)
calculated_rate = rate amount/12/monthly_qty
calculated_fee = calculated_rate * qty
vatable_qty = sum of qty with vatable = Y
vat = calculated_rate * vatable_qty * 0.12
if param = jan 16 - feb 15 (period is bound on effective start and end date)
output table expected:
datetime | person | qty | monthly_qty | calc_rate | calc_fee | vat_qty | vat
--------------------------------------------------------------------------------------------------
2016-01-16 00:00:00 | p1 | 21 | 40 | 156/12/40 | calc_rate * 21 | 10 | calc_rate * 10 * 0.12
2016-01-16 01:00:00 | p1 | 9 | 40 | 156/12/40 | calc_rate * 9 | 9 | calc_rate * 9 * 0.12
2016-01-16 02:00:00 | p2 | 10 | 40 | 156/12/40 | calc_rate * 10 | 10 | calc_rate * 10 * 0.12
2016-02-15 00:00:00 | p1 | 16 | 16 | 156/12/16 | calc_rate * 16 | 16 | calc_rate * 16 * 0.12
(1) I am getting the wrong total_qty_per_month
(monthly_qty) - for january, it includes 2016-01-15 in the total, actual: 50, expected: 40 (10 + 11 + 9 + 10 only)
EDIT: Here's my updated SQL: (I am using a view)
select it.datetime, it.person, 'rate2'::varchar as rate_used,
sum(it.qty) as qty,
rl.amount, rl.effective_start_date, rl.effective_end_date,
sum(sum(it.qty)) over w_month as total_qty_per_month,
rl.amount / 12 / sum(sum(it.qty)) over w_month as calculated_rate,
((rl.amount / 12 / sum(sum(it.qty)) over w_month) * sum(qty)) as calculated_fee,
sum(case when it.vatable = 'Y' then it.qty else 0 end) as vatable_qty
from input_table it
inner join rate_lookup_table rl on it.datetime between rl.effective_start_date and rl.effective_end_date
where it.person_type='PT1' and rl.rate_type = 'rate2'
group by it.datetime, it.person, rl.amount, rl.effective_start_date, rl.effective_end_date
window w_month as (partition by date_trunc('month', it.datetime))
order by it.datetime
I need to get the sum of the window function based on effective_start_date
and effective_end_date
of the rate lookup table
.
Upvotes: 1
Views: 129
Reputation:
As far as I can tell, you can do that using a join with between
and a window function to calculate the sum per month:
select it.datetime, it.person, it.qty, rl.amount, rl.rate_type,
rl.amount / 12 / sum(it.qty) over (partition by date_trunc('month', it.datetime)) as calculated_rate
from rate_lookup_table rl
join input_table it on it.datetime between rl.effective_start_date and effective_end_date
where rl.rate_type = 'rate2';
date_trunc('month', it.datetime)
"normalized" the date to the start of the month, so all values for the same month are the same. So the window function will sum up all quantities for the same month.
Based on your sample data, this returns:
datetime | person | qty | amount | rate_type | calculated_rate
--------------------+--------+-----+--------+-----------+----------------
2016-01-16 00:00:00 | p1 | 10 | 156 | rate2 | 0.45
2016-01-16 01:00:00 | p1 | 9 | 156 | rate2 | 0.45
2016-01-16 02:00:00 | p2 | 10 | 156 | rate2 | 0.45
2016-02-15 00:00:00 | p1 | 8 | 156 | rate2 | 1.63
The calculated_fee and vat can be derived from the calculated_rate. To not repeat the expression you can use a derived table:
select *,
calculated_rate * qty as calculated_fee,
calculated_rate * qty * 0.12 as vat
from (
select it.datetime, it.person, it.qty, rl.amount, rl.rate_type,
rl.amount / 12 / sum(it.qty) over (partition by date_trunc('month', it.datetime)) as calculated_rate
from rate_lookup_table rl
join input_table it on it.datetime between rl.effective_start_date and effective_end_date
where rl.rate_type = 'rate2'
) t;
Upvotes: 3