Неправильные результаты сравнения дат в SQL Server 2008 R2 - PullRequest
0 голосов
/ 02 марта 2012

У меня есть SQL-запрос LINQ 2, который дает мне список результатов за февраль 2012 года. Результирующее предложение where равно

DECLARE @p0 DateTime = '2012-02-01 00:00:00.000'
DECLARE @p1 DateTime = '2012-02-29 23:59:59.999'
....
WHERE (CONVERT(DATE, [t0].[DatePlaced]) >= @p0) AND (CONVERT(DATE, [t0].[DatePlaced]) <= @p1)

Когда это запустится, я получаю результаты за 3/1/2012, а также все результаты за 2 / 2012.

Если я изменю предложение where на использование BETWEEN, тогда результаты будут содержать только даты за февраль.

WHERE [t0].[DatePlaced] BETWEEN @p0 AND @p1

Я использую .net 4 и SQL Server 2008 R2 с пакетом обновления 1 и без.

Переключение дат на 01.03.2011 и даты окончания моего запроса на '2011-02-28 23:59:59.999' дало те же результаты.

Есть ли другой способ получить результаты всего за 2/2012, кроме использования BETWEEN, который LINQ 2 SQL не поддерживает?

Ответы [ 3 ]

4 голосов
/ 02 марта 2012

.999 округляется до полуночи следующего дня.Вы можете проверить это:

DECLARE @p1 DateTime = '2012-02-29 23:59:59.999';
SELECT @p1;

Что вы получаете?

Вместо того, чтобы пытаться выяснить последний момент сегодняшнего дня (который будет отличаться в зависимости от типа данных и точности),вместо этого вам нужен открытый диапазон дат:

DECLARE @p0 DATE = '2012-02-01',
        @p1 DATE = '2012-03-01';
....
WHERE [t0].[DatePlaced] >= @p0
AND [t0].[DatePlaced] < @p1

Еще проще было бы просто передать начальную дату и сказать:

DECLARE @p0 DATE = '2012-02-01';

....
WHERE [t0].DatePlaced >= @p0
AND [t0].DatePlaced < DATEADD(MONTH, 1, @p0)

Для некоторых сложных идей о дате и временилучшие практики:

Для получения дополнительной информации о причинах BETWEEN (расширение >= AND <=) является злом:

3 голосов
/ 02 марта 2012

Если вам нужно часто выбирать по месяцам, вы можете добавить в таблицу два вычисляемых столбца - один для месяца, другой для года:

ALTER TABLE dbo.YourTable
ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED

ALTER TABLE dbo.YourTable
ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED

Эти два новых столбца автоматически вычисляются SQL Server, они сохраняются (например, часть хранилища таблицы), и вы даже можете поместить в них индекс, если это имеет смысл для вас.

Теперь вы можете использовать запрос вроде:

SELECT (columns)
FROM dbo.YourTable
WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2

чтобы получить все данные за февраль 2012 года.

Это классический компромисс между скоростью и пространством - сохраняя два дополнительных столбца для каждой строки, вам нужно больше места - но в свою очередь, запросы становятся проще, и если у вас есть индекс для (DatePlacedYear, DatePlacedMonth), ваши запросы должен (в идеале) быть довольно быстрым.

0 голосов
/ 02 марта 2012

Вместо использования AddMilliseconds(-1) попробуйте использовать AddMilliseconds(-3)

См. этот вопрос как SQL Server обрабатывает миллисекунды

...