I have a table containing transactional events for customers:
table: events
| id | cust_id | date | amount |
|------|----------|----------------------------|--------|
| 78 | 211 | 2010-06-18 20:10:00.000000 | 20 |
| 84 | 211 | 2010-07-18 05:53:00.000000 | 35 |
| 91 | 211 | 2010-07-27 05:45:00.000000 | 25 |
| 2136 | 211 | 2011-02-14 20:07:00.000000 | 5000 |
| 2947 | 211 | 2011-02-21 20:29:25.000000 | 22 |
| 2945 | 211 | 2011-03-14 20:48:26.000000 | 22 |
I want to produce a year and month aggregation of the sum of the amounts, but where the month periods correspond to the customer's subscription period. This period has a specific start date, for example the 20th of the month.
The query can take the inputs:
customer id
– the customer to generate the report forstart day of period
– the day of the month on which the "month" should start
Here is a query that naively groups by month without the custom period:
SELECT
extract(YEAR FROM date) AS year,
extract(MONTH FROM date) AS month,
sum(amount) AS amount
FROM events
WHERE cust_id = 211
GROUP BY 1, 2
ORDER BY year, month;
Example output of this naive query:
| year | month | amount |
|------|-------|--------|
| 2010 | 6 | 20 |
| 2010 | 7 | 60 |
| 2011 | 2 | 5022 |
| 2011 | 3 | 22 |
But, given that start day for customer 211 is the 20th of the month, I want the actual output to be:
| year | month | amount |
|------|-------|--------|
| 2010 | 5 | 20 | from May 20 - June 19
| 2010 | 6 | 35 | from June 20 - July 19
| 2010 | 7 | 25 | from July 20 - Aug 19
| 2011 | 1 | 5000 | from Jan 20 - Feb 19
| 2011 | 2 | 44 | from Feb 20 - March 19
I'm at a loss for how to go from my naive query to the query I need to generate this output.
Best Answer
First it calculates
month
according to next formula:Obviously you can change day 20 by no matter which other day.
dbfiddle here
These are values returned by CTE:
dbfiddle here