There are a lot of bad answers and habits in this thread, when it comes to selecting based on a date range where the records might have non-zero time values - including the second highest answer at time of writing.
Never use code like this: Date between '2011/02/25' and '2011/02/27 23:59:59.999'
Or this: Date >= '2011/02/25' and Date <= '2011/02/27 23:59:59.999'
To see why, try it yourself:
DECLARE @DatetimeValues TABLE
(MyDatetime datetime);
INSERT INTO @DatetimeValues VALUES
('2011-02-27T23:59:59.997')
,('2011-02-28T00:00:00');
SELECT MyDatetime
FROM @DatetimeValues
WHERE MyDatetime BETWEEN '2020-01-01T00:00:00' AND '2020-01-01T23:59:59.999';
SELECT MyDatetime
FROM @DatetimeValues
WHERE MyDatetime >= '2011-02-25T00:00:00' AND MyDatetime <= '2011-02-27T23:59:59.999';
In both cases, you'll get both rows back. Assuming the date values you're looking at are in the old datetime type, a date literal with a millisecond value of 999 used in a comparison with those dates will be rounded to millisecond 000 of the next second, as datetime isn't precise to the nearest millisecond. You can have 997 or 000, but nothing in between.
You could use the millisecond value of 997, and that would work - assuming you only ever need to work with datetime values, and not datetime2 values, as these can be far more precise. In that scenario, you would then miss records with a time value 23:59:59.99872, for example. The code originally suggested would also miss records with a time value of 23:59:59.9995, for example.
Far better is the other solution offered in the same answer - Date >= '2011/02/25' and Date < '2011/02/28'
. Here, it doesn't matter whether you're looking at datetime or datetime2 columns, this will work regardless.
The other key point I'd like to raise is date and time literals. '2011/02/25'
is not a good idea - depending on the settings of the system you're working in this could throw an error, as there's no 25th month. Use a literal format that works for all locality and language settings, e.g. '2011-02-25T00:00:00'
.