I have a table with a list of markets and corresponding amounts related to those markets
Market | Amount |
---|---|
A | 10 |
B | 30 |
C | 50 |
D | 10 |
10 |
I would like this $10 in the blank market to be allocated to the rest of the markets proportionately based on amounts excluding the blank market (ex. amount(A)/sum(A B C D))
The desired output is:
Market | Amount |
---|---|
A | 11 |
B | 33 |
C | 55 |
D | 11 |
I think I can query it using multiple CTEs, but wanted to see if it's possible to allocate using as few CTEs as possible or not using CTE at all.
CodePudding user response:
So with this CTE just for data:
with data(market, amount) as (
select * from values
('A', 10),
('B', 30),
('C', 50),
('D', 10),
(null, 10)
)
we can:
select d.*
,sum(iff(d.market is null, d.amount,null)) over() as to_spread
,sum(iff(d.market is not null, d.amount,null)) over() as total
,div0(d.amount, total) as part
,part * to_spread as bump
,d.amount bump as result
from data as d
qualify market is not null
to get:
MARKET | AMOUNT | TO_SPREAD | TOTAL | PART | BUMP | RESULT |
---|---|---|---|---|---|---|
A | 10 | 10 | 100 | 0.1 | 1 | 11 |
B | 30 | 10 | 100 | 0.3 | 3 | 33 |
C | 50 | 10 | 100 | 0.5 | 5 | 55 |
D | 10 | 10 | 100 | 0.1 | 1 | 11 |
We can then fold a few of those steps up:
select d.*
,d.amount div0(d.amount, sum(iff(d.market is not null, d.amount,null)) over()) * sum(iff(d.market is null, d.amount,null)) over() as result
from data as d
qualify market is not null
MARKET | AMOUNT | RESULT |
---|---|---|
A | 10 | 11 |
B | 30 | 33 |
C | 50 | 55 |
D | 10 | 11 |
seems these results are on fixed point numbers, the truncation of division, will loss "amounts", which could be spread fairly, but that might require a second pass.