SQL Server Date SELECT does not return all available values

tv6aics1  于 2023-03-28  发布在  其他
关注(0)|答案(2)|浏览(111)

I have been trying to call out all available dates from the last 3 months but unfortunately my "formula" seems to always leave out 1 day.

For example, if today is the 23-03-2023 and I want to return all the dates from the last 3 months I would expect to see everything from the 23-12-2022 but also INCLUDING the 23rd of December.

What I am doing is returning everything starting from today's date -3 months (so from the 24th of December) and excludes always today's date.

My database is on a SQL Server 2016.

select * from TABLE where DATE_COLUMN >= dateadd(month, -3, getdate())
s3fp2yjn

s3fp2yjn1#

Remove the time part from GetDate() before filtering:

select * from TABLE where DATE_COLUMN >= dateadd(month, -3, cast(getdate() as date))
hmae6n7t

hmae6n7t2#

Use cast(dateadd(month, -3, getdate()) as date) to convert the filter value to a date without a time part.

GetDate() returns the current date and time. When you compare a datetime to a date , both are treated as datetime values, ie with a date component. 2023-12-31 01:00 will always be later than 2023-12-31 so all entries up to that time will be lost.

You can also use cast(GetDate() as date) . DATEADD doesn't really care. Pick the expression that's easier to read.

To exclude today's date you still need to cast to a date . :

where DATE_COLUMN >=cast(dateadd(month, -3, getdate())) and 
      DATE_COLUMN < cast(getdate() as date)

What about cast(someDateTime as date)='2023-03-20' ?

This would produce the correct results but have bad performance. If this was a non-date type, it would be very bad performance because the query engine wouldn't be able to use any indexes covering someDateTime . It would have to calculate the cast result for every single row and then filter them. This is called a non-SARGable query or, less scientifically, a Row-By-Agonizing-Row (RBAR).

With date types, SQL Server will convert this into a date range query, equivalent to :

WHERE someDateTime >='2023-03-20' and someDateTime <'2023-03-21'

While this can use indexes, it can't use the statistics gathered for the actual stored dates so the server can still end up with a bad execution plan. If, for example, almost all rows pass the criteria using an index would be a waste of time. The server would have no way of knowing this though and would still use the index.

This is discussed at great length at Cast to date is sargable but is it a good idea? .

The solution in this case is to write the range expression explicitly:

WHERE someDateTime >=@dateParam and someDateTime <DATEADD(d,1,@dateParam)

相关问题