SQL日期过滤

时间:2017-03-01 10:09:51

标签: sql sql-server sql-server-2012

只是一个相当普遍的日期过滤问题......

我有一个包含YYYYMMDD(没时间)的日期字段。 当我在当月查找交易时,如果我这样做,我会得到不同的结果......

and MyDateField between '2017-03-01' and '2017-03-31'

如果我这样做......

and Year(MyDateField) = '2017' and Month(MyDateField) = '3'

看起来像'之间的关系。方法是排除3月1日发生的任何事情(其他交易是未来日期)。

为什么会这样?

这些是'之间的结果。方法...

20170303
20170327
20170309
20170324
20170331
20170306

这些是'年/月'结果...

20170303
20170327
20170309
20170324
20170301
20170331
20170306
20170301

数据存储为nvarchar(8) - 我应该先转换为日期吗?

1 个答案:

答案 0 :(得分:4)

BETWEEN具有包容性。

and MyDateField between '2017-03-01' and '2017-03-31'

与:

相同
and MyDateField >= '2017-03-01' 
and MyDateField <= '2017-03-31'

我唯一的解释是MyDateField的类型 date,但是datetime或类似的可能有时间部分。

表中的某些值实际上具有此非零时间组件。

因此,您的查询应如下所示:

and MyDateField >= '20170301' 
and MyDateField < '20170401'

有关详细信息,请参阅Aaron Bertrand的Bad habits to kick : mis-handling date / range queries

好吧,在您说列类型为nvarchar(8)后,很明显字符串'2017-03-01'和'20170301'的比较无法导致什么都好。

使用BETWEEN时,您需要比较字符串,而不是日期。当您使用YEARMONTH时,服务器会将您的nvarchar(8)值转换为场景后面的日期(以及废品效果)。

可以将日期存储为nvarchar(8),但是你需要将它们与相同格式的字符串进行比较,如下所示(没有破折号):

and MyDateField >= '20170301' 
and MyDateField <= '20170331'

最好将它们存储为char(8),但将它们存储为date会更好。 date为3个字节,nvarchar(8)为至少17个字节。

请参阅Bad habits to kick : choosing the wrong data type