I have this table that tracks budget usage of an advertising campaign. It has those fields:
- AdvertiserID
- Budget Scope ID: It’s the campaign ID
- Budget: Budget of the campaign (es. 100$/day) and it can change during the day
- Percentage: Percentage of the budget spent today (from 00:00 to 23:59)
- Usage_updated_timestamp: Timestamp event
Now I want to plot a sawtooth chart of the total cost (budget*percentage/100) aggregating by AdvertiserId and summing the cost for all campaigns.
I expect the cost to go up during the day and fall to 0 at midnight because percentage is 0.
The problem is that I do not have records all at the same timestamp but they are randomly updated during the day. So I tried with this query:
SELECT
advertiser_id,
usage_updated_timestamp,
SUM(budget*budget_usage_percentage/100) AS cost
FROM budget_usages
GROUP BY 1,2
But as you can see the cost decrease during the day because for the same timestamp I have a record for one campaign and not for the other. I cannot use date_trunc(‘hour’, timestamp) because they are random. The only thing I know is that the percentage resets to 0 at midnight.
My idea is that I need to consider, for each minute, the last updated value for each existing campaign (budget_scope_id) and sum it.
FIDDLE: https://dbfiddle.uk/sTxfucZ1
My desidered results is:
Timestamp | Cost | Notes |
---|---|---|
2024-01-01 7:00 | 250 | 1000 * 0.25 |
2024-01-01 8:00 | 1600 | 3000 * 0,45 + 1000 * 0,25 |
2024-01-01 10:00 | 1650 | 3000 * 0.45 + 1000 * 0.30 |
2
Answers
Yes, except that you cannot just sum the values since they are already cumulated (per day). So you would first need to get the delta of each update, per campaign (and considering the day). This is possible using the
LAG
window function. Then afterwards you can sum these deltas, across campaigns, with a window function that aggregates per day. Throw in some zero values for restarting at each midnight and you get(updated fiddle)
LATERAL
subqueries andwindow functions
let you define how far back you want to reach, then look back from a row: demoYou don’t need to
round()
to get rid of trailing zeroes if you instead cast to::float
– their default output format rounds those off. I’m showing rounded to 2 decimal places to simplify the demo.The
distinct on
picks the latest budgets and spendings for eachadvertiser_id
andbudget_scope_id
for each row you’re looking back from.