我正在使用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
运算符遍布这个旧系统,似乎并没有正确地提取所有数据。我只想先从一些人那里得到澄清。谢谢!
答案 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