I have a query that groups data by week. I would like to include a partial week at the start and end of the result but the partial week does not count the records.
SELECT
series_interval,
coalesce(conversion_count, 0) AS conversion_count
FROM (
SELECT
series::date AS series_interval
FROM
generate_series(
date_trunc('week', to_date('2024-12-10', 'YYYY-MM-DD')), -- Added 6 days to start date to get following week
date_trunc('week', to_date('2024-12-23', 'YYYY-MM-DD')),
INTERVAL '1 week'
) AS series
UNION
SELECT to_date('2024-12-04', 'YYYY-MM-DD')
) AS series -- Start date (middle of week)
LEFT JOIN (
SELECT
date_trunc('week', "conversions"."created_at") AS agg_interval,
count("conversions"."id") AS conversion_count
FROM
"conversions"
INNER JOIN "commissions" ON "commissions"."conversion_id" = "conversions"."id"
WHERE
"conversions"."created_at" >= '2024-12-02'
AND "conversions"."created_at" <= '2024-12-23 23:59:59.999999'
GROUP BY
agg_interval
) c ON c."agg_interval" = series."series_interval";
The date buckets are:
4th => 8th (5 days)
9th => 15th (7 days)
16th => 22nd (7 days)
23rd => 23rd (1 day – restricted by WHERE
so final partial week is what I want)
And the query result is:
series_interval | conversion_count |
---|---|
2024-12-04 | 0 |
2024-12-09 | 411 |
2024-12-16 | 368 |
2024-12-23 | 32 |
I understand why I get 0 for the first row 0 – because 2024-12-04
is not a Monday and this is how the date truncation / grouping works.
How can I get the count for 4th => 8th?
2
Answers
For simplicity, I’l use CTE
params
to setstart_date
andend_date
for query. Further, the literal constants are not used in the query.Source data for example see in fiddle
.
Generate series (report frame) include start_date, start date of weeks between start_date and end_date.
Column report_date is used as output, series_interval – for join with grouped data.
Extra dates are cut off by the filter
WHERE created_at between start_date and end_date
.fiddle
If you want
first data bucket would aggregated on the full week (starting on 2nd Dec)
– (It’s not clear why) use where filterYou have two non-standard week definitions: 1 starting other the Monday and 1 not being a full week. This complicates the matter somewhat but not excessively. The following uses a recursive CTE to generate the base periods beginning with your non-standard starting week and following periods each ending on the following each Monday and beginning the next period (it does however not deal with the short week). Once the periods are defined a second CTE handles the short week while converting each to a daterange. The main query then just counts the rows falling into each date range. See demo here.
NOTE: The above makes use of a
next_day()
function. Oracle provides a function to do this. I found it so useful that I wrote a Postgres version to do the same. It is provided in the demo.