我在SQL Server 2005中使用日期时间字段遇到了一个奇怪的错误。日期时间字段显示的是毫秒级精度,但看起来并不总是使用毫秒。这是我的测试查询:
SELECT col1, YEAR(col1) AS yr, MONTH(col1) AS mn, DAY(col1) AS dy
FROM mytable
WHERE col1 >= '2009-12-31 00:00:00.0' AND col1 <= '2009-12-31 23:59:59.999'
ORDER BY col1
在我的结果中,我得到了:
col1 | yr | mn | dy ----------------------------+------+----+---- 2009-12-31 00:00:00:00.000 | 2009 | 12 | 31 2010-01-01 00:00:00:00.000 | 2010 | 1 | 1
问题是我得到了2010-01-01的日期,即使它不应该小于或等于“2009-12-31 23:59:59.999”。但是,如果我将查询更改为使用“2009-12-31 23:59:59.99 8 ”,它就可以正常工作(不会返回2010日期时间)。
这是一个错误,还是这就是SQL Server的工作原理?如果这是它的工作方式,有什么理由吗?我遇到了从MySQL迁移的一些查询,这些查询按预期工作(即使MySQL甚至不存储毫秒!)。
答案 0 :(得分:12)
SQL Server
将时间部分存储为午夜的1/300
秒长标记数。
23:59:59.999
四舍五入到最接近的刻度,恰好是第二天的00:00:00.000
。
SELECT CAST(CAST('2009-12-01 00:00:00.000' AS DATETIME) AS BINARY(8)),
CAST(CAST('2009-12-01 23:59:59.997' AS DATETIME) AS BINARY(8)),
CAST(CAST('2009-12-01 23:59:59.999' AS DATETIME) AS BINARY(8))
0x00009B8F 00000000 0x00009B8F 018B81FF 0x00009B90 00000000
在第一个值中,日期部分0x9B8F
(39823
)是自Jan 1st, 1900
以来的天数,时间部分0
是数字从午夜开始的蜱虫。
在第二个值中,0x018B81FF
(25919999
或24 * 60 * 60 * 300 - 1
)是自午夜以来最大可能的刻度数。
最后,第三个值在时间部分中有0
,日期部分增加了一个。
答案 1 :(得分:2)
这不是错误。这是完全预期的行为。 看这里:datetime and smalldatetime
您应该将其更改为
WHERE col1 >= '2009-12-31 00:00:00.0' AND col1 < '2010-01-01'
答案 2 :(得分:1)
对于所有浮点类型,日期/时间实际上是一种浮点值,您应该尽量避免相等的比较。
所以而不是:
WHERE x <= 10.999
你应该这样做:
WHERE x < 11
因此,不是列出您想要包含的最后一个值,而是列出您想要排除的第一个值,通常这在边界是整数时更有效,因为它们有更大的机会在域中准确表示类型。
在您的特定情况下,我会将其更改为:
WHERE ... col1 < '2010-01-01 00:00:00.000'
^
| ^-- changed to 2010
^-- changed <= to <
答案 3 :(得分:1)
这也是为什么不建议在日期之间使用'Between'比较运算符。 'Between'是一个包容性的比较(包含两端匹配的值),并且如上所述,您应该在两者之间做一个独有的版本,例如 bottomvalue&lt;测试值&lt; topvalue