Работает ли МЕЖДУ с датами на самом деле в SQL SERVER 2008 - PullRequest
4 голосов
/ 14 февраля 2009

Согласно cdonner , в его ответе здесь и в его блоге .

Он утверждает, что МЕЖДУ с датой дает противоречивые результаты

Из своего блога:

select
    case when '9/1/08' between '9/1/08' and '9/15/08'
        then 'in' else 'out' end as s1,
    case when '9/1/08' between '8/28/08' and '9/1/08'
        then 'in' else 'out' end as s2

s1   s2
---- ----
in   in

(1 row(s) affected)
select
    case when '1/1/08' between '1/1/08' and '2/1/08'
        then 'in' else 'out' end as s1,
    case when '1/1/08' between '12/31/07' and '1/1/08'
        then 'in' else 'out' end as s2

s1   s2
---- ----
in   out

(1 row(s) affected

Обратите внимание, что ответ S2 во втором запросе показывает "Out", когда ясно должна быть указана дата.

Согласно cdonner , причина этого в том, что:

[наименее значимая цифра типа DateTime в SQL составляет 3 мсек

Я думаю, что причина намного проще, чем это. Я думаю, это потому, что он использует строки, а не даты в своем запросе.

Пожалуйста, извините за мой SQLServer-иш. Я говорю в основном о Oracle, так что это может быть некрасиво. Но когда я беру его запрос, который доказывает, что есть проблема, и заменяю его строки переменными даты и времени, я получаю правильный вывод.

DECLARE @Jan108 datetime
DECLARE @Feb108 datetime
DECLARE @Dec3107 datetime

SET @Jan108 = '1/1/08'
SET @Feb108 = '2/1/08'
SET @Dec3107 = '12/31/07'

select
    case when @Jan108 between @Jan108 and @Feb108
        then 'in' else 'out' end as s1,
    case when @Jan108 between @Dec3107 and @Jan108
        then 'in' else 'out' end as s2

Что правильно?

NB: это не попытка урегулировать спор или начать пламенную войну. Я действительно хочу понять, является ли SQL Server BETWEEN менее функциональным, чем Oracle BETWEEN. У нас нет такой проблемы в Oracle.

Ответы [ 8 ]

6 голосов
/ 14 февраля 2009

В Oracle:

select
    case when '1/1/08' between '1/1/08' and '2/1/08'
        then 'in' else 'out' end as s1,
    case when '1/1/08' between '12/31/07' and '1/1/08'
        then 'in' else 'out' end as s2
FROM dual

in out

Здесь вы сравниваете строки, а не даты.

Нет ничего BETWEEN 12/31/07 and 1/1/08, поскольку 2 идет после / в ASCII

4 голосов
/ 14 февраля 2009

Я должен использовать что-то вроде этого:

Declare @BeginDate SmallDateTime
Declare @EndDate SmallDateTime
Set @BeginDate = '2007-08-01'
Set @EndDate = '2007-08-31'

Select *
From dbo.table1 a
Where a.session_date Between @BeginDate + ' 00:00:00' And @EndDate + ' 23:59:59'
Order By a.session_date asc

Для получения правильного значения между датой и временем

2 голосов
/ 14 февраля 2009

SQL-сервер хранит значения даты и времени в виде числа. Например, 0 - 1900-01-01 00: 00: 00.000

Пример, который вы приводите в своем вопросе, подвержен проблемам округления, подобно тому, как значение с плавающей запятой 1.0 хранится как 0.99999 ...

Для точного сравнения дат вы должны привести значение к типу datetime, а затем выполнить сравнение.

SELECT
CASE 
    WHEN cast('1/1/08' as datetime) 
        BETWEEN cast('1/1/08' as datetime) AND cast('2/1/08' as datetime) 
    THEN 'in' ELSE 'out' 
END AS s1,
CASE 
    WHEN cast('1/1/08' as datetime) 
        BETWEEN cast('12/31/07' as datetime) AND cast('1/1/08' as datetime) 
    THEN 'in' ELSE 'out' 
END AS s2

Что приведет к ожидаемому результату: s1 == in, s2 == in

1 голос
/ 14 февраля 2009

Вы правы, что его код содержит ошибки из-за сравнения строк.

Однако, если вы используете тип datetime, а не новый тип date, это не имеет значения. Причина в том, что вы все равно обычно не хотите инклюзивный поиск, и поэтому вместо кода, подобного этому:

SELECT * FROM [MyTable] WHERE MyDateColumn BETWEEN @StartDate AND @EndDate

вы обычно пишете это так:

SELECT * FROM [MyTable] WHERE MyDateColumn >= @StartDate AND MyDateColumn < @EndDate

где @EndDate на самом деле больше, чем день, который вы действительно хотите.

Я ожидаю, что проблема будет исправлена ​​для нового типа Date, но у меня нет SQL Server 2008 под рукой, поэтому я не могу его протестировать.

0 голосов
/ 19 февраля 2013

Очень полезная дискуссия!

У меня были похожие проблемы, решаемые с помощью CAST и CONVERT, как в:

cast (CONVERT (varchar (8), [PostDate], 112) AS DATE) МЕЖДУ «2013-01-01» И «2013-01-31»

Работает как шарм, что подтверждается множеством подробных проверок.

Требуется «Cast (» (поверьте мне, у меня есть лысые пятна, чтобы доказать это). Но не нужно было объявлять переменные и т. Д.

Интересуется обратной связью, если я скучаю по лодке с методом или моим ответом.

Спасибо!

0 голосов
/ 02 мая 2011

Просто никогда не используйте МЕЖДУ со значениями даты и времени. В MySQL я могу сделать

created >= CURDATE() - INTERVAL 1 DAY AND created < CURDATE()

для ограничения созданного (всего) вчера.

С МЕЖДУ '2011-05-02' И '2011-05-02 23:59:59' Я буду играть на одной секунде в разрешении и пропущу создание '2011-05-02 23:59 : 59,001'

.
0 голосов
/ 26 сентября 2009

Код в блоге был ерундой, и я в долгу перед Марком за то, что указал мне на это. Проблема существует. Это не имеет ничего общего с BETWEEN, но с округлением (которое может привести к отказу BETWEEN в определенных обстоятельствах). В то время как SQL Server выполняет округление, .Net нет, и я столкнулся с проблемами с несколькими вставками за очень короткий период времени, когда я предположил, что у меня были разные значения даты и времени, но из-за округления они стали одинаковыми в базе данных. Сообщение было исправлено давно, и примеры кода все еще работают на SQL Server 2008.

Если вы выполните этот запрос, вы увидите, что я имел в виду:

select convert(varchar(32), convert(datetime,
                            '9/1/08 00:00:00.005'), 121);
0 голосов
/ 14 февраля 2009

Потому что он совершенно не прав - он сравнивает строки

если вы приведете их к дате или замените их переменными даты, это сработает:

select
    case when CAST('JAN 01 2008' as smalldatetime)
        between CAST('JAN 01 2008' as smalldatetime)
        and CAST('FEB 01 2008' as smalldatetime)
        then 'in' else 'out' end as s1,
    case when CAST('JAN 01 2008' as smalldatetime)
        between CAST('DEC 31 2007' as smalldatetime)
        and CAST('JAN 01 2008' as smalldatetime)
        then 'in' else 'out' end as s2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...