views:

477

answers:

5

I'm trying to retrieve all rows inserted during a specific month.

SELECT 
    dbo.Post.UserId, 
    dbo.Post.Tags, 
    dbo.Post.CommentCount, 
    dbo.Post.Status,  
    dbo.Post.PostDate, 
    dbo.Post.[Content], 
    dbo.Post.Title, 
    dbo.Post.PostId, 
    dbo.[User].DisplayName 
FROM  
    dbo.Post INNER JOIN
    dbo.[User] ON dbo.Post.UserId = dbo.[User].UserId 
Where PostDate >=  DATEADD(mm, 0, DATEDIFF(mm, 0, '01/28/2009')) 
    AND  PostDate <=  DATEADD(mm, 0, DATEDIFF(mm, 0, '01/28/2009'))

Any idea's?

+2  A: 
 WHERE PostDate >=  DATEADD(mm, DATEDIFF(mm, 0, '01/28/2009'), 0)
   AND PostDate <  DATEADD(mm, 1 + DATEDIFF(mm, 0, '01/28/2009'), 0)
David B
i didn't see this one +1
dotjoe
A: 
@dtInput = '01/28/2009'

-- subtract current days (less one) to get to start of month
set @dtStart = dateadd( dd, 1 - datepart( dd, @dtInput ), @dtInput )

-- add a month, then subtract 1 sec to get 23:59:59 on last day of month
set @dtEnd = dateadd( ss, -1, dateadd( mm, 1, @dtStart ))

SELECT ... WHERE PostDate between @dtStart and @dtEnd
MikeW
test your queries, there are mistakes with parenthesises
Max Gontar
+1  A: 

You want to create the starting moment of that month and the starting moment of the next month, then take the dates from and including the starting moment, and until but not including the next starting moment.

I.e. the result should be equivalent to:

Where PostDate >= '01/01/2009' and PostDate < '02/01/2009'

This will get you exactly that month and no overlapping onto the next month.

The expression DATEDIFF(mm, 0, '2009-01-28') will give you the number of months from 01/01/1900, so you should use that date as the third parameter in the DATEADD:

DATEADD(mm, DATEDIFF(mm, 0, '01/28/2009'), '01/01/1900')

To get the starting moment of the next month you just use '02/01/1900' as offset. Let's put that in the condition:

Where
  PostDate >= DATEADD(mm, DATEDIFF(mm, 0, '01/28/2009'), '01/01/1900') and
  PostDate < DATEADD(mm, DATEDIFF(mm, 0, '01/28/2009'), '02/01/1900')
Guffa
IMO you should use 0 as the third parameter in dataadd. It should match the second parameter in datadiff. Then instead of using '02/01/1900' you would add 1 to the datadiff result.
dotjoe
Better yet, use a real date in both places. Then you can use a better date than the mystic zero date, like '01/01/2000' for example. It doesn't matter what date really, as long as it's the same in both places.
Guffa
a string isn't a real date...'2/1/2009' could be jan. 2nd!?! zero will always be the base date. cast(0 as datetime). nothing mystic about it.
dotjoe
No, on the server that the OP is using, that date literal has a very specific meaning, it means feb 1st, it can NOT be jan. 2nd. The database server doesn't change date format from one end of the query to the next.
Guffa
+2  A: 

You mention for a "given month", I'm assuming a month number from 1 to 12. If you start with a date and just want everything that falls within that month:

@month = datepart(mm, 'given date');
@year  = datepart(yy, 'given date');

Then use:

Where 
   datepart(mm, Post.Postdate) = @month
   and datepart(yy, Post.PostDate) = @year

like that.

Ron

(I added the year in case you care about that. :-))

Ron Savage
this may be usefull if we don't care about the year
Max Gontar
This is fine as long as data volumes are low, but it will always table scan, so will get slow as volumes rise. The other solutions can benefit from an index on the date column, very much so if volumes are high and the index is clustered.
Mike Woodhouse
@year takes care of the year. This query indicates that a certian year/month is what you're looking for. A date range wouldn't necessarily tell me that. But I'm sure the comments would ;)
Jeff O
+1  A: 

This will do it.

Where PostDate >=  DATEADD(mm, DATEDIFF(mm, 0, '01/28/2009'), 0) 
    AND  PostDate <  DATEADD(mm, DATEDIFF(mm, 0, '01/28/2009') + 1, 0)

Also, I usually set up my date range before the query so I don't have to put date functions in the where clause.

declare @from datetime;
declare @thru datetime;

set @from = DATEADD(mm, DATEDIFF(mm, 0, '01/28/2009'), 0);
set @thru = DATEADD(mm, 1, @from);

...
Where PostDate >=  @from 
        AND  PostDate <  @thru
dotjoe