intermediatedate-time MySQL MariaDB SQL Server PostgreSQL SQLite
Group Rows By Month
Bucket dates into month starts, then aggregate counts or totals per month.
Created Last updated 5/5 supported engines validation-green1 example2 scenarios
Docker-validated Not currently validation-green
Example 1
Count orders and total revenue per month
March has two orders worth 100 total. April has three orders worth 150 total. The query first maps each order_date to the first day of its month, then aggregates on that derived month value.
SELECTDATE_FORMAT (order_date, '%Y-%m-01') AS month_start,
COUNT(*) AS total_orders,
SUM(amount) AS total_amount
FROM
orders
GROUPBYDATE_FORMAT (order_date, '%Y-%m-01')
ORDERBY
month_start;
SELECTTO_CHAR(DATE_TRUNC('month', order_date::TIMESTAMP), 'YYYY-MM-DD') AS month_start, COUNT(*) AS total_orders, SUM(amount) AS total_amount FROM orders GROUPBYDATE_TRUNC('month', order_date::TIMESTAMP) ORDERBY month_start;
SELECT
strftime ('%Y-%m-01', order_date) AS month_start,
COUNT(*) AS total_orders,
SUM(amount) AS total_amount
FROM
orders
GROUPBY
strftime ('%Y-%m-01', order_date)
ORDERBY
month_start;
Expected result
month_start
total_orders
total_amount
2024-03-01
2
100
2024-04-01
3
150
The month-bucketing function differs by engine, but the grouped monthly totals are identical.
Useful when
Where this command helps.
building monthly order or revenue summaries
grouping event data into reporting periods before charting
Explanation
What the command is doing.
Monthly reporting usually needs two steps: convert each date to its month bucket, then aggregate on that bucket. The exact truncation function differs by engine, but the pattern is the same. Once each row maps to the first day of its month, GROUP BY can count rows, sum amounts, or compute other aggregates per month.