MySQL: find week start/end given week number

I have a table with some dated records. I wanted to do some weekly reports on this data. MySQL has a nifty function dubbed WEEK() which will return a week number. It allows you to break your data into week long intervals very easily. For example, the following query will tell me how many records came in each week:

SELECT COUNT(*), WEEK(mydate)
FROM mytable
GROUP BY WEEK(mydate)

The problem here is, that the output is totally meaningless to me as I do not have a clue what does week 36 mean. What I really want is to have on the screen is a nice, human readable date interval - the beginning and ending date of any given week.

Surprisingly, this turns out the be a major pain in the ass. There is no simple function that will yield a week interval (or start/end date of a week) given a week number. You have to find these dates manually. Here is how I did it:

SELECT
    COUNT(*) AS reports_in_week,
    DATE_ADD(mydate, INTERVAL(1-DAYOFWEEK(mydate)) DAY),
    DATE_ADD(mydate, INTERVAL(7-DAYOFWEEK(mydate)) DAY)
FROM
    mytable
GROUP BY
    WEEK(mydate)

How does it work? The DAYOFWEEK() function returns an integer ranging from 1 (Sunday) to 7 (Saturday). So if mydate happens to be Tuesday we get the following statements:

DATE_ADD(mydate, INTERVAL -2 DAY)

which essentially means “subtract 2 days from mydate (which is that week’s Sunday) and also:

DATE_ADD(mydate, INTERVAL 4 DAY)

which yields the date of that week’s Friday.

One would think that there would be a function to accomplish this automatically, but alas there is none. I think this is as simple as it gets. I hope this helps someone, because it took me quite a while to figure this out.

Related Posts:

  • MySQL Performance Tips
  • Dump MySQL table into CSV file
  • Monster Weekend (but not for me)
  • MySQL Admin 1.0.19: libmysqlx.dll Error
  • DST Readines Test for MySQL and PHP
  • Dreamhost Outage
  • MySQL no Longer Provides Free Binaries
  • MySQL: How to get the key of last inerted row in PHP
  • MINUS query in MySQL
  • Project Idea

  • 17 Responses to “MySQL: find week start/end given week number”

    1. Gravatar Maxime CANADA Says: Reply to this comment

      You can use MAX and MIN to get the group by maximum and minimum values, this includes date fields.

      E.G.:
      SELECT
      COUNT(*) AS reports_in_week,
      MIN(mydate) as week_start,
      MAX(mydate) as week_end,
      FROM
      mytable
      GROUP BY
      WEEK(mydate)

      Posted using Mozilla Firefox Mozilla Firefox 2.0 on Windows Windows XP
    2. Gravatar Luke UNITED STATES Says: Reply to this comment

      Cool! It’s a good idea! Thanks!

      I played around with it, but it’s not exactly what I wanted. What I really needed is a query that will display date intervals for the weeks in which I had reports. In other words, I want to have dates of respective Sunday and Saturday for each week, not the dates of the first and last report submitted that week.

      But thanks for the tip anyway. mrgreen

      Posted using Mozilla Firefox Mozilla Firefox 2.0 on Linux Linux
    3. Gravatar Ed Davis UNITED STATES Says: Reply to this comment

      I used this to get orders placed in the same week as the day I’m asking the question…it might be put in an iterative loop to get what you were after…

      SELECT * FROM `va_orders` WHERE WEEK(`order_placed_date`) = WEEK(CURDATE())

      Posted using Mozilla Firefox Mozilla Firefox 1.5.0.9 on Windows Windows XP
    4. Gravatar Luke UNITED STATES Says: Reply to this comment

      Ed - yeah that would work. But then I’m sending n queries to the database (where n is number of iterations in the loop). It really puts a strain on the database and will be slower. You also get concurrency issues if another process is updating records as you loop…

      On the other hand a single SQL query is not only easier on the DB, but it will likely be further optimized by the database scheduler.

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.1 on Windows Windows XP
    5. Gravatar Walter UNITED STATES Says: Reply to this comment

      Thanks for this write up. It really helped me as I was looking to group data in the same way.

      One thing I caught is that if you simply do GROUP BY week(mydate) you will group together records that fall in the same week, but in different years. The data set I was working with happened to span over multiple years so this was making my result inaccurate. The solution I came up with was to create a GROUP BY value that would be unique per each year/week combination.

      SELECT
      DATE(DATE_ADD(mydate, INTERVAL(1-DAYOFWEEK(mydate)) DAY)) as StartOfWeek,
      SUM(somefield)
      FROM
      sometable
      GROUP BY
      YEAR(mydate) + .01 * WEEK(mydate)

      This works in MySQL 5.0. I don’t remember off the top of my head if previous versions allowed expressions like that in the GROUP BY clause. That expression will evaluate to [year].[week] for each date. So the 14th week in 2007 would be 2007.14 while the 14th week in 2008 would be 2008.14. Seems clumsy but it worked for me.

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.6 on Windows Windows Vista
    6. Gravatar Luke Maciak UNITED STATES Says: Reply to this comment

      Hmm… I think my data spanned at least 2 years. I will need to revisit this.

      Just of the top of my head - would another Group By clause fix this? As in

      GROUP BY WEEK(mydate), YEAR(mydate)

      Haven’t tested this cause I’m in a hurry/

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.6 on Ubuntu Linux Ubuntu Linux
    7. Gravatar Walter UNITED STATES Says: Reply to this comment

      Luke Maciak said:

      Hmm… I think my data spanned at least 2 years. I will need to revisit this.

      Just of the top of my head - would another Group By clause fix this? As in

      GROUP BY WEEK(mydate), YEAR(mydate)

      Haven’t tested this cause I’m in a hurry/

      I just tried this on my data set and it gave the same results as my initial stab at the problem. Performance was the same, but it’s easier to understand.

      Thanks!

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.6 on Windows Windows Vista
    8. Gravatar Luke Maciak UNITED STATES Says: Reply to this comment

      Hehe. Wow, my MySQL-Fu is still strong. ) Glad I could help.

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.6 on Windows Windows XP
    9. Gravatar Stuart UNITED KINGDOM Says: Reply to this comment

      I’ve been looking for an answer to this problem all morning and your solution worked great. I don’t know if it has any performance benefits, but MySQL has a YEARWEEK() function which stops you having to group by WEEK() and YEAR().

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.6 on Windows Windows XP
    10. Gravatar shaun Says: Reply to this comment

      select DATE_ADD(’2007-09-07′,INTERVAL(2-DAYOFWEEK(’2007-09-07′))DAY);

      swipe the date with what ever date you want to pass

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.6 on Windows Windows XP
    11. Gravatar Luke Maciak UNITED STATES Says: Reply to this comment

      @Stuart - Thanks Stuart! Good tip!

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.6 on Ubuntu Linux Ubuntu Linux
    12. Gravatar Matt Wood UNITED KINGDOM Says: Reply to this comment

      This works…

      SELECT * FROM Table WHERE WEEK(’Date’,4) = 30;

      It shows all the dates that are in the week number 30. I use mode 4 as Week 1 is the first week of the year, starting with a Sunday.

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.7 on Windows Windows XP
    13. Gravatar Snehapadma SaaS INDIA Says: Reply to this comment

      Hi All!

      What if I want to aggregate data for periods between Monday and Sunday? Is there any straight forward way to do that? e.g. like setting up the first weekday as Monday in the system?

      This discussion shows that Firefox is popular.

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.11 on Windows Windows XP
    14. Gravatar olivier Says: Reply to this comment

      For iso weeks (week starting on mondays, week numbering starting at 1) you can get the first day of the week “week_id” of the year “year” using
      DATE_ADD( MAKEDATE(year,1), INTERVAL( -(((DAYOFWEEK(MAKEDATE(year,1))+1)%7)-3) + (week_id-1)*7 ) DAY)
      simple, no ? )

      Posted using Mozilla Firefox Mozilla Firefox 2.0.0.12 on Windows Windows XP
    15. Gravatar Julio PERU Says: Reply to this comment

      i have a question… how can i group by weeks… but starting on wednesday or tuesday?

      Posted using Opera Opera 9.50 on Windows Windows 2000
    16. Gravatar Sid UNITED STATES Says: Reply to this comment

      I have a script which has the following in the beginning, can someone explains what does it mean in mysql:

      SET @aStart = CURDATE() - INTERVAL 1 WEEK;  
      SET @aEnd = @aStart + INTERVAL 1 WEEK;
      SET @aStartlastweek = @aStart - INTERVAL 1 WEEK;
      SET @aEndlastweek = @aEnd - INTERVAL 1 WEEK;
      SET @aStartlast2week = @aStart - INTERVAL 2 WEEK;
      SET @aEndlast2week = @aEnd - INTERVAL 2 WEEK;
      SET @aStartlast3week = @aStart - INTERVAL 3 WEEK;
      SET @aEndlast3week = @aEnd - INTERVAL 3 WEEK;
      SET @aStartlast4week = @aStart - INTERVAL 4 WEEK;
      SET @aEndlast4week = @aEnd - INTERVAL 4 WEEK;
       
       
      SET @bStartNorm = 5;
      SET @bEndNorm = 23;
      SET @bRspCode = 999;
      SET @bMaxAvg  = 120;
      Posted using Internet Explorer Internet Explorer 6.0 on Windows Windows XP
    17. Gravatar Luke Maciak UNITED STATES Says: Reply to this comment

      @Sid: What do you mean? I think it is sort of self explanatory.

      @aStart will be the date exactly a week before today
      @aEnd will be a week from @aStart - which is today
      @aStartlastweek will be a date 1 week prior to @aStart

      And so on. When it says:

      SET @foo = @bar - INTERVAL n WEEK

      it just means to count back n weeks from the date in @bar and put the result in @foo. The last 4 lines are just assignments.

      Does that make sense?

      Posted using Mozilla Firefox Mozilla Firefox 3.0.1 on Ubuntu Linux Ubuntu Linux

    Leave a Reply

    XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <pre lang=""> <em> <i> <strike> <strong>

    [Quote selected]