All existing (working) answers have one of two problems:
- They will ignore indexes in the examined column.
- Will (potentially) selects data that is not intended without corrupting your results.
1. Ignored indices:
For the most part, when a column search calls a function called on it (including implicitly, as for CAST ), the optimizer should ignore the indexes in the column and search for each record. Here is a quick example:
We deal with timestamps, and most RDBMSs tend to store this information as an increasing value of some type, usually a long number or a BIGINTEGER milli / nanosecond. Thus, the current time looks / stores as follows:
1402401635000000 -- 2014-06-10 12:00:35.000000 GMT
You don't see the meaning of 'Year' ( '2014' ) here, do you? In fact, there is a fairly complicated math to translate back and forth. Therefore, if you call any retrieval / date functions in the found column, the server should do all this math just to find out if you can include it in the results. On small tables, this is not a problem, but as the percentage of selected rows decreases, it becomes a big and big leak. Then in this case you do it a second time to ask about MONTH ... well, you get an image.
2. Unintentional data:
Depending on the specific version of SQL Server and the column data types, using BETWEEN (or similarly included upper bounds: <= ) may result in the selected incorrect data . Essentially, you can end up including data from midnight on the “next” day or excluding some of the “current” daytime entries.
What you should do:
Thus, we need a way that is safe for our data, and we will use indexes (if they are viable). The correct path is:
WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth
Given that there is only one month, @startOfPreviousMonth can easily be replaced with / inferred:
DATEADD(month, -1, @startOCurrentfMonth)
If you need to get the beginning of the current month on the server, you can do this through the following:
DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
A brief explanation is here. The initial DATEDIFF(...) will get the difference between the beginning of the current era ( 0001-01-01 - AD, CE, whatever), essentially returning a large integer. This is the number of months before the start of the current month. Then we add this number to the beginning of the era that is at the beginning of this month.
So your full script might / should look something like this:
DECLARE @startOfCurrentMonth DATETIME SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0) SELECT * FROM Member WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth)
Thus, all operations with dates are performed only once, one value at a time; the optimizer is free to use indexes and no invalid data will be included.