If you abandon the x BETWEEN a AND b
pattern in favour of one that could roughly be expressed as
x BEGINS WITH a
ENDS BEFORE b
(which, of course, is not valid SQL syntax but x >= a AND x < b
would be a decent replacement), you will end up with both a
and b
having same granularity (specifically, months, because each of the two points would be the beginning of a month).
In this case it is very opportune because it will allow you to factorise calculation of both a
and b
nicely. But before I get there, let me tell (or remind) you about this date/time truncation technique in SQL Server:
DATEADD(unit, DATEDIFF(unit, SomeFixedDate, YourDateTime), SomeFixedDate)
In your case, the unit
would be MONTH
. As for SomeFixedDate
, there is an established practice of using 0 there for brevity, 0 representing the date of 1900-01-011.
So, using this technique, the beginning of the current month would be calculated as
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
That would be the end of your interval. The beginning of the interval would be same except you would subtract 12 from the DATEDIFF's result, and so the complete condition to match the range would look like this:
WHERE StartDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 12, 0)
AND StartDate < DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
If that still looks a mouthful to you, you could try getting rid of the repetition of DATEDIFF(MONTH, 0, GETDATE())
. You could view it as some abstract month number and reference it as such in both DATEADD calls. The CROSS APPLY syntax would help you with that:
…
CROSS APPLY (
SELECT DATEDIFF(MONTH, 0, GETDATE())
) AS x (MonthNo)
WHERE StartDate >= DATEADD(MONTH, x.MonthNo-12, 0)
AND StartDate < DATEADD(MONTH, x.MonthNo , 0)
Yes, that seems factorised all right. However, it might not lend itself well to readability. Someone (even yourself, at some later point) might look at it and say: "Huh, MonthNo
? What in the world is that? Ah, that number…" If I were to factorise your interval calculation, I might consider this instead:
…
CROSS APPLY (
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
) AS x (ThisMonth)
WHERE StartDate >= DATEADD(YEAR, -1, x.ThisMonth)
AND StartDate < x.ThisMonth
I admit, though, that readability is not a perfectly objective criterion and sometimes one chooses to write one way or the other based on one's personal tastes/preferences.
1Although hard-coding a date as an integer value is not a normal practice, I would argue that this truncation technique is a special case where using 0 in place of a datetime value should be okay: that usage appears to be so widespread that it may by now have become a "fixed expression" among those using it and is, therefore, unlikely to cause much confusion.