我有一个名为book_data的表,其中batch_dt作为sql server中varchar类型的列名。
当我通过查询时
SELECT DISTINCT batch FROM book_data
它给了我以下结果
batch_dt
-------------
2012-10-31
-------------
2012-11-01
-------------
2012-11-02
-------------
2012-11-03
-------------
.
.
.
现在我正在做的是获取两个日期之间的记录总数。相当简单的查询。
SELECT COUNT(*) FROM book_data WHERE CONVERT(varchar(12),CONVERT(datetime,batch_dt),101) BETWEEN '11/02/2012' and '10/31/2012'
结果是 的 112
只需将月份从 02 更改为 2 ,查询就会给我 218 结果
SELECT COUNT(*) FROM book_data WHERE CONVERT(varchar(12),CONVERT(datetime,batch_dt),101) BETWEEN '11/2/2012' and '10/31/2012'
为什么这种不同的行为?
答案 0 :(得分:3)
改为使用CAST(batch_dt AS DATE)
,并以YYYYMMDD
格式以语言中立的方式传递日期。通过这种方式,它将被归为日期,而不是varchar
:
SELECT COUNT(*)
FROM book_data
WHERE CAST(batch_dt AS DATE)
BETWEEN '20121102' and '20121130'
但是,这不安全,如果barch_dt
中的任何值格式错误,您将收到转换错误。在这种情况下,您可以添加ISDATE(batch_dt) = 1
以确保它是有效的数据时间。但最好将此列数据类型DateTime
。
需要注意的另一件事:是SQL Server中BETWEEN
非对称,这意味着BETWEEN '11/02/2012' and '10/31/2012'
被评估为:
DATE >= '11/02/2012'
AND
DATE <= '10/31/2012'
永远不会成立,它适合你的原因是日期被比作字符串而不是日期。但你必须保持BETWEEN the small value and the biggest value
。
答案 1 :(得分:2)
SELECT COUNT(*)
FROM book_data
WHERE CONVERT(DATETIME,batch_dt,101) BETWEEN '11/2/2012' and '10/31/2012'
这会更合适
答案 2 :(得分:2)
您将字符串与BETWEEN
进行比较。如果您这样做,您需要确保以正确的顺序进行比较=&gt; YYYYMMDD MM:SS是一个正确的订单。
如果可以,请添加类型为datetime
的列,并在数据库中存储实际日期时间值。如果您不能这样做,您可以拆分值并自己构建日期值。这比使用CONVERT()
或CAST()
慢得多,但您可以确保它甚至可以使用错误的日期字符串。
您可以使用PATINDEX(),LEFT(),RIGHT()
关键字获取所需的值,或使用split()函数(您可以找到许多版本的Google,例如https://codereview.stackexchange.com/questions/15125/sql-server-split-function-optimized)。如果您使用拆分功能,则按/
拆分,然后从位置获取年,月,日。
但最好还是将正确的日期时间值存储在数据库中。
答案 3 :(得分:1)
您会得到这种不同的行为,因为您不比较日期而是比较字符串/ varchars。
对于Date
(或DateTime
),10/2/2012
与10/02/2012
相同。
但是对于string
,这些值(当然)是不同的。就像您将'abcd'
与'ab0cd'