2

我有一个名为 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'

为什么会有这种不同的行为?

4

4 回答 4

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以确保它是有效的数据时间。但是最好把这列设为 datatype 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

于 2013-01-22T07:43:34.123 回答
2

您将 string 与BETWEEN. 如果这样做,您需要确保以正确的顺序进行比较 => YYYYMMDD MM:SS 将是正确的顺序。

如果可以,请添加具有类型的列datetime并将实际日期时间值存储在数据库中。如果你不能这样做,你可以拆分这些值并自己建立一个日期值。这比仅使用 a 慢得多CONVERT()CAST()但您可以确保它即使使用错误的日期字符串也能正常工作。

您可以使用PATINDEX(),LEFT(),RIGHT()关键字来获取所需的值,也可以使用 split() 函数(您可以在 google 上找到许多版本,例如https://codereview.stackexchange.com/questions/15125/sql-server-split-function-优化)。如果您使用拆分功能,则拆分,/然后从职位中获取年、月、日。

但最好还是将正确的日期时间值存储在您的数据库中。

于 2013-01-22T07:53:22.810 回答
1
SELECT COUNT(*) 
FROM book_data 
WHERE CONVERT(DATETIME,batch_dt,101) BETWEEN '11/2/2012' and '10/31/2012'

这样会更合适

于 2013-01-22T07:41:57.697 回答
1

您会得到这种不同的行为,因为您不比较日期而是比较字符串/varchars。

对于 a Date(或DateTime),10/2/2012与 相同10/02/2012

但是对于string,这些值(当然)是不同的。就好像你会'abcd'比较'ab0cd'

于 2013-01-22T07:55:06.167 回答