views:

324

answers:

1

I've got a query (for use in bug tracker.net) that calculates the number of bugs by week by status. But the query returns the week number, what I really want is the first date of the week

select datepart(wk, DateAdd(day, 0, DateDiff(day, 0, bg_reported_date)))
       as [week], bg_status , st_name as [status], count(*) as [count] 
  from bugs inner join statuses on bg_status = st_id 
 group by datepart(wk, DateAdd(day, 0, DateDiff(day, 0, bg_reported_date))),
          bg_status, st_name
 order by [week], bg_status

The part that gets the week number is

datepart(wk, DateAdd(day, 0, DateDiff(day, 0, bg_reported_date))) as [week]

It returns this output:

week        bg_status   status                                        count
----------- ----------- --------------------------------------------- ------
22          1           new                                           1
22          5           closed                                        32

But it would be better to say the first date of each week, eg 01-01-2010, then 08-01-2010, etc

Question is not a duplicate of http://stackoverflow.com/questions/1267126/how-do-you-get-the-week-start-date-and-week-end-date-from-week-number-in-sql (answer says how to get week start from a date not from a week number)

Not a duplicate of http://stackoverflow.com/questions/662379/calculate-date-from-week-number (question asks for c#)

Not a duplicate of http://stackoverflow.com/questions/1036613/get-first-date-of-week-from-provided-date (question asks for javascript)

I did search but couldn't find this question answered for SQL Server (2010 if it matters)

+2  A: 

If you think about it in the right way, the answer to SO 1267126 can be applied to your problem.

Each of the bug reported dates that you have in the group maps to the same week. By definition, therefore, each of those bug dates must also map to the same start of the week. So, you run the 'start of the week from given date' calculation on the bug report dates, as well as the week number calculation, and group by both (modestly ghastly) expressions, and end up with the answer you seek.

SELECT DATEPART(wk, DATEADD(day, 0, DATEDIFF(d, 0, bg_reported_date))) [week],
       DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1), bg_reported_date)
       AS [weekstart], bg_status, st_name AS [status], COUNT(*) AS [count] 
  FROM bugs INNER JOIN statuses ON bg_status = st_id 
 GROUP BY DATEPART(wk, DATEADD(day, 0, DATEDIFF(day, 0, bg_reported_date))),
       DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1), bg_reported_date),
       bg_status, st_name
 ORDER BY [week], bg_status

Since bg_reported_date is a DATETIME (see the comment; it includes a time component), it is necessary to cast it to DATE before determining the week-start (but the week number expression doesn't need the cast, and the 'day of week' part of the week start expression doesn't need the cast either):

SELECT DATEPART(wk, DATEADD(day, 0, DATEDIFF(d, 0, bg_reported_date))) [week],
       DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1),
               CAST(bg_reported_date AS DATE)) AS [weekstart],
       bg_status, st_name AS [status], COUNT(*) AS [count] 
  FROM bugs INNER JOIN statuses ON bg_status = st_id 
 GROUP BY DATEPART(wk, DATEADD(day, 0, DATEDIFF(day, 0, bg_reported_date))),
       DATEADD(dd, -(DATEPART(dw, bg_reported_date)-1),
               CAST(bg_reported_date AS DATE),
       bg_status, st_name
 ORDER BY [week], bg_status

NB: Untested code!

Jonathan Leffler
That's not grouping correctly because bg_reported_date includes the time. I'll see what happens when the time is removed first. It will make that expression much worse - bg_reported_date is in there 3 times, so will have to have the time removed 3 times.
JK
Sweet, thanks. Its an ugly bunch of DATETHIS and DATETHAT functions, but works great.
JK