具有日期的BETWEEN实际上是否在SQL SERVER 2008中有效

时间:2009-02-13 22:13:36

标签: sql-server datetime

根据cdonner,在他的回答here和他的blog中。

他声称BETWEEN与日期会产生不一致的结果

来自他的博客:

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 ,原因是:

SQL中DateTime类型的最低有效位是3毫秒

我认为原因要简单得多。我认为这是因为他在查询中使用字符串而不是日期。

请原谅我的SQLServer-ish。我主要讲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 个答案:

答案 0 :(得分:6)

在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

答案 1 :(得分:4)

我必须使用这样的东西:

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

获得正确的BETWEEN日期时间

答案 2 :(得分:2)

SQL Server将日期时间值存储为数字。例如,0是1900-01-01 00:00:00.000

您在问题中提供的示例受到舍入问题的影响,类似于浮点值1.0的存储方式为0.99999 ...

要准确比较日期,您可以将值转换为日期时间类型,然后进行比较。

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

答案 3 :(得分:1)

你的代码因字符串比较而存在缺陷是正确的。

但是,如果您使用的是日期时间类型而不是新的日期类型,则无关紧要。原因是你通常不想要包容性搜索,而不是像这样的代码:

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

你通常会这样写:

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

其中@EndDate实际上比您真正想要的那一天更大。

我希望新的Date类型的问题已得到修复,但我没有SQL Server 2008的便利,所以我无法测试它。

答案 4 :(得分:0)

因为他完全错了 - 它正在比较字符串

如果你把它们转换为日期时间或者用日期变量替换它们就可以了:

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

答案 5 :(得分:0)

博客上的代码是胡说八道,我欠马克指出这一点。 这个问题存在。它与BETWEEN无关,但与舍入(在某些情况下可能导致BETWEEN失败)。虽然SQL Server进行了循环,但.Net没有,并且我在很短的时间内遇到了多个插入的问题,我认为我有不同的日期时间值,但由于四舍五入,它们在数据库中变得相同。 该帖子很久以前就得到了纠正,代码示例仍适用于SQL Server 2008。

如果您运行此查询,您将看到我所指的内容:

select convert(varchar(32), convert(datetime,
                            '9/1/08 00:00:00.005'), 121);

答案 6 :(得分:0)

永远不要将BETWEEN用于日期时间值。在MySQL中,我可以做到

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

将限制创建到(整个)昨天。

BETWEEN'2011-05-02'和'2011-05-02 23:59:59'我将赌博一秒钟的决议,并且会错过创建的'2011-05-02 23:59 :59.001'

答案 7 :(得分:0)

非常有用的讨论!

我有类似的问题,通过使用CAST和CONVERT解决,如:

施放(CONVERT(varchar(8),[PostDate],112)AS DATE)在'2013-01-01'和'2013-01-31'之间

像魅力一样工作,经多次详细验证验证。

“施放(”是必需的(相信我,我有秃头来证明它)。但不必声明变量等。

如果我错过了方法或我的回应,那么会对反馈感兴趣。

谢谢!