日期之间的T-SQL混乱

时间:2011-03-25 14:45:26

标签: tsql sql-server-2000 between

我正在使用SQL Server 2000中的T-SQL,我有一个表TRANSACTIONS,其日期列TRANDATE定义为DateTime,其中许多列与此问题无关。

该表填充了多年的交易。我遇到了代码,测试,让我困惑。有一个简单的SELECT,就像这样:

SELECT TRANDATE, RECEIPTNUMBER FROM TRANSACTIONS WHERE TRANDATE BETWEEN '12/01/2010' and '12/31/2010' ORDER BY TRANDATE

并且它没有返回我知道的那两行数据。

使用上面的语句,它按顺序返回的最后一行有一个TRANDATE: 2010-12-31 00:00:00.000

当我修改如下所示的语句时,我会获得该表中2010年12月的额外两行:

SELECT TRANDATE, RECEIPTNUMBER FROM TRANSACTIONS WHERE TRANDATE BETWEEN '12/01/2010 00:00:00' and '12/31/2010 23:59:59' ORDER BY TRANDATE

我试图找出为什么BETWEEN运算符在使用上面的第一个SELECT时,在12/31/2010的24个句点中不包含所有行。为什么它需要将明确的小时数添加到SELECT语句中,如第二个修改后的语句中所示,以使其拉出正确的行数?

是否因为TRANDATE定义为“DATETIME”的方式?

基于这个发现,我认为我将不得不经历所有这些旧代码,因为这些BETWEEN运算符遍布这个旧系统,似乎并没有正确地提取所有数据。我只想先从一些人那里得到澄清。谢谢!

5 个答案:

答案 0 :(得分:14)

日期是一个时间点,而不是时间跨度。

'12/31/2010'也是一个观点。也就是说,这是12月31日的午夜 在这一点之后发生的一切都被忽略了 这正是你想要的行为(即使你还没有意识到)。

当你选择省略时间部分时,不要认为它被神奇地假设为"any"。它将是"all zeroes",也就是午夜。

如果您想在查询中包含整天,而无需在时刻 {{1}之间指定23:59:59(顺便提一下,excludes the last second of the day在当天和第二天的时刻 23:59:59中,您可以使用严格的不等式(00:00:00>)来限制您想要的第一个时间点:

<

或通过比较投放到WHERE TRANDATE >='12/01/2010 00:00:00' and TRANDATE < '01/01/2011' 的日期值:

DATE

(可以将这种类型的强制转换放在WHERE CAST(TRANDATE AS DATE) between '12/01/2010' and '12/31/2010' 子句it is sargable)中。

答案 1 :(得分:4)

正如您所发现的,如果您没有指定输入日期的时间,则默认为日期早晨的午夜。所以12/31/2010在那天开始的午夜停止。

要获取2010年12月31日的所有日期,您可以指定时间,就像您一样,或者在结束日期添加一天。没有时间,2011年1月1日在2010年12月31日的午夜时分结束。所以,你可以做BETWEEN 12/1/2010 AND 1/1/2011。您可以使用DATEADD在SQL中添加日期,以便更轻松。

添加一天的第二种方法存在一些风险。您将获得2011年1月1日的任何记录,其时间为00:00:00。

以下是执行DATEADD

的一种方法
DECLARE @FromDate datetime, @ToDate datetime
// These might be stored procedure input parameters
SET @FromDate = '12/1/2010'
SET @ToDate = '12/31/2010'

SET @ToDate = DATEADD(d, 1, @ToDate)

然后以常规方式在@ToDate词组的WHERE子句中使用BETWEEN

答案 2 :(得分:3)

'12 / 01/2010'表示'12 / 01/2010 00:00:00'和'12 / 31/2010'表示'12 / 31/2010 00:00:00'。这就是为什么在12/31/2010当天晚些时候的日期时间值将从查询结果中排除。

答案 3 :(得分:2)

如果我这样做,你的预期结果是什么

Insert "12/31/2010" into your datetime column?

确切地说:12-31-2010 00:00:00

那么为什么你会期望它作为查询的参数不同呢?

答案 4 :(得分:1)

你已经回答了自己的问题。您观察到的 SQL Server的工作方式。

如果您需要确认,则此MSDN document有关于此的说明

  

当时间部分未指定时,它   默认为12:00 A.注意一行   包含时间部分   在上午12点之后在1998-0105会   此查询不会返回,因为   它超出了范围。

修改

至于你的评论,日期时间本质上是一个浮点值。

以下脚本显示SQL Server使用的数字 当您的上限为40541(12/31/2010)时,不能包含40541.9749(12/31/2010 23:23:59)

DECLARE @ADateTime1 DATETIME
DECLARE @ADateTime2 DATETIME
DECLARE @ADateTime1AsFloat FLOAT
DECLARE @ADateTime2AsFloat FLOAT

SET @ADateTime1 = '12/31/2010'
SET @ADateTime2 = '12/31/2010 23:23:59'

SET @ADateTime1AsFloat = CAST(@ADateTime1 AS FLOAT)
SET @ADateTime2AsFloat = CAST(@ADateTime2 AS FLOAT)

SELECT @ADateTime1AsFloat, @ADateTime2AsFloat