How to group by week in MySQL?

Viewed 139293

Oracle's table server offers a built-in function, TRUNC(timestamp,'DY'). This function converts any timestamp to midnight on the previous Sunday. What's the best way to do this in MySQL?

Oracle also offers TRUNC(timestamp,'MM') to convert a timestamp to midnight on the first day of the month in which it occurs. In MySQL, this one is straightforward:

TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))

But this DATE_FORMAT trick won't work for weeks. I'm aware of the WEEK(timestamp) function, but I really don't want week number within the year; this stuff is for multiyear work.

9 Answers

If you need the "week ending" date this will work as well. This will count the number of records for each week. Example: If three work orders were created between (inclusive) 1/2/2010 and 1/8/2010 and 5 were created between (inclusive) 1/9/2010 and 1/16/2010 this would return:

3 1/8/2010
5 1/16/2010

I had to use the extra DATE() function to truncate my datetime field.

SELECT COUNT(*), DATE_ADD( DATE(wo.date_created), INTERVAL (7 - DAYOFWEEK( wo.date_created )) DAY) week_ending
FROM work_order wo
GROUP BY week_ending;

Previous Sunday:

STR_TO_DATE(CONCAT(YEARWEEK(timestamp,2),'0'),'%X%V%w')

Previous Monday:

STR_TO_DATE(CONCAT(YEARWEEK(timestamp,3),'1'),'%x%v%w')

DATE_FORMAT(date,format) reference:

  • %V - Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X
  • %v - Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x
  • %w - Day of the week (0=Sunday..6=Saturday)
  • %X - Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
  • %x - Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v

I like the week function in MySQL, but in my situation, I wanted to know which week of the month a row was in. I utlized this solution:

where run_date is a timestamp like 2021-02-25 00:00:00

concat ( 
        date_format(run_date, '%Y-%m'), 
        ' wk ', 
        (week(run_date,1) - ( week(date_format(run_date, '%Y-%m-01')) - 1))
        ) as formatted_date

This outputs:

2021-02-23 --->    2021-02 wk 4
2021-02-25 --->    2021-02 wk 4
2021-02-11 --->    2021-02 wk 2
2021-03-02 --->    2021-03 wk 1

The idea behind this is that I want to know (with relative certainty) which week of the month in question did the date occur?

So we concatenate:

date_format(run_date, '%Y-%m') to get 2021-02

then we add the literal text string wk

then we use: week(run_date, 1) to get the week (1 to start Monday) of this record, (which would be 7 because 02/21/2021 is in the 7th week of the year, and we subtract whatever the week is on the 1st day of this same month - the week() for 2021-02-01 is 5, because it is in the 5th week of the year:

(week(date_format(run_date, '%Y-%m-01'))

Unfortunately, this will start out the counting at 0, which people don't like, so we subtract 1 from the last part of the concatenation result so that the "week" start at 1.

This may be a good option:

SELECT
 year(datetime_field) as year_date, week(datetime_field) as week_date
FROM
 bd.table
GROUP BY
 year_date, week_date;

It would look like this:

  • '2020', '14'
  • '2020', '15'
  • '2020', '16'
  • '2020', '17'
  • '2020', '18'
Related