Запрос T-SQL возвращает элементы, которых не должно быть

Вот сценарий. Рассматриваемый столбец называется «datein», а его тип — «datetime». У меня есть три строки со значением «2009-10-01 00:00:00.000» для «datein». Почему этот запрос возвращает вышеупомянутые строки?

SELECT  *
FROM    t_call AS tc
WHERE   tc.datein >= '2009-09-30 00:00:00.000'
        AND tc.datein <= '2009-09-30 23:59:59.999'

С использованием

SELECT  *
FROM    t_call AS tc
WHERE   tc.datein BETWEEN '2009-09-30 00:00:00.000'
        AND '2009-09-30 23:59:59.999'

возвращает тот же результат


person GregD    schedule 01.10.2009    source источник


Ответы (5)


Это отсутствие точности в тысячных долях секунды. Вместо этого попробуйте ".997".

документация MSDN DateTime

Запустите это, и вы увидите:

declare @dt datetime

select @dt = '2009-09-30 23:59:59.999'
select @dt
person Austin Salonen    schedule 01.10.2009
comment
@GregD: то же самое отсутствие разрешения. Время DateTime подходит только для каждых 3 или 4 миллисекунд. - person Joel Coehoorn; 02.10.2009
comment
Потрясающий. Я отметил ваш ответ как правильный. Также большое спасибо за ссылку. @Joel Спасибо за дополнительную информацию. - person GregD; 02.10.2009
comment
@Austin Не обращайте внимания на мой комментарий (который я с тех пор удалил). Я приводил его к smalldatetime вместо datetime. - person GregD; 02.10.2009
comment
Тип даты DATETIME2 в SQL Server 2008 будет иметь точность до 100 нс, поэтому у вас не будет этой проблемы с DATETIME2. - person marc_s; 02.10.2009

точность DATETIME составляет 0,00333 секунды. Поэтому вам нужно перейти к «2009-09-30 23:59:59.998», чтобы он не округлялся до 1 октября.

Например:

select '2009-09-30 23:59:59.994', 
  cast('2009-09-30 23:59:59.994' as datetime)
union all select '2009-09-30 23:59:59.995', 
  cast('2009-09-30 23:59:59.995' as datetime)
union all select '2009-09-30 23:59:59.996', 
  cast('2009-09-30 23:59:59.996' as datetime)
union all select '2009-09-30 23:59:59.997', 
  cast('2009-09-30 23:59:59.997' as datetime)
union all select '2009-09-30 23:59:59.998', 
  cast('2009-09-30 23:59:59.998' as datetime)
union all select '2009-09-30 23:59:59.999', 
  cast('2009-09-30 23:59:59.999' as datetime)

возвращает:

2009-09-30 23:59:59.994 2009-09-30 23:59:59.993
2009-09-30 23:59:59.995 2009-09-30 23:59:59.997
2009-09-30 23:59:59.996 2009-09-30 23:59:59.997
2009-09-30 23:59:59.997 2009-09-30 23:59:59.997
2009-09-30 23:59:59.998 2009-09-30 23:59:59.997
2009-09-30 23:59:59.999 2009-10-01 00:00:00.000
person Remus Rusanu    schedule 01.10.2009

Какой тип столбца? Если это дата и время, попробуйте привести значения, которые вы сравниваете, к дате и времени; если это строка (char, nchar, varchar, nvarchar), какую сортировку и т. д. вы используете для столбца?

person Lucero    schedule 01.10.2009
comment
Тип столбца «дата-время». добавлю в оп - person GregD; 02.10.2009

Согласно документации MSDN

Дата и время с 1 января 1753 г. по 31 декабря 9999 г. с точностью до одной трехсотой секунды (эквивалентно 3,33 миллисекунды или 0,00333 секунды). Значения округляются до приращения 0,000, 0,003 или 0,007 секунды, как показано в таблице.

В приведенном примере на этой странице вы должны закончить запрос на .997, чтобы получить ожидаемые результаты.

person eKek0    schedule 01.10.2009

Безопасный способ написания этих запросов выглядит следующим образом:

SELECT  *
FROM    t_call AS tc
WHERE   tc.datein >= '2009-09-30T00:00:00.000'
        AND tc.datein < '2009-10-01T00:00:00.000''
person Steve Kass    schedule 02.10.2009