SQL"之间"不包括在内

JBu*_*ace 117 sql t-sql sql-server date sql-server-2008

我有这样的查询:

SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'
Run Code Online (Sandbox Code Playgroud)

但即使第一次有数据,这也没有结果.

created_at看起来2013-05-01 22:25:19,我怀疑它与时间有关?怎么解决这个问题?

如果我执行更大的日期范围,它可以正常工作,但它应该(包含)也可以使用单个日期.

Gor*_*off 261

包容性的.您正在将日期时间与日期进行比较.第二个日期被解释为当天开始时的午夜.

解决此问题的一种方法是:

SELECT *
FROM Cases
WHERE cast(created_at as date) BETWEEN '2013-05-01' AND '2013-05-01'
Run Code Online (Sandbox Code Playgroud)

另一种解决方法是使用显式二进制比较

SELECT *
FROM Cases
WHERE created_at >= '2013-05-01' AND created_at < '2013-05-02'
Run Code Online (Sandbox Code Playgroud)

Aaron Bertrand在日期(这里)有一篇很长的博客文章,在那里他讨论了这个和其他日期问题.

  • 为了完整性这个好的答案,我建议使用`dateadd`来获得第二天. (14认同)
  • 你永远不应该在`where`子句中输入一个列,因为它会丢失它所拥有的任何索引.这是一个非常糟糕的模式. (10认同)
  • @TimLehner为了得到一个好的答案,我会使用ISO-8601格式的'20130501'.对于使用dateformat dmy的非美国人,您可以得到:`set dateformat dmy; select month(cast('2013-05-01'as datetime)); = 1` (7认同)
  • @scottb就个人而言,我觉得每次想要显示,导出,导入或编写带有日期时间的类时都必须转换为日期时间很烦人.我认为SQL Server具有大量内置功能,可以在大多数情况下操作和比较日期时间. (3认同)
  • @RichardTheKiwi-我相信_explicit_位使用的是一个在一个结束时关闭的时间间隔(`&gt; =`)在另一个结束时打开的时间间隔(`&lt;`),并检查超过指定结束日期的一天。 (2认同)
  • @布齐纳斯。。。您的评论明确不适用于在 SQL Server 中转换为日期。 (2认同)

Use*_*ady 39

假设BETWEEN语法中的第二个日期引用被神奇地认为是"一天的结束",但这是不真实的.

即这是预期的:

SELECT * FROM Cases 
WHERE created_at BETWEEN the beginning of '2013-05-01' AND the end of '2013-05-01'

但真正发生的是这个:

SELECT * FROM Cases 
WHERE created_at BETWEEN '2013-05-01 00:00:00+00000' AND '2013-05-01 00:00:00+00000'

这相当于:

SELECT * FROM Cases WHERE created_at = '2013-05-01 00:00:00+00000'

问题是的感知/预期大约一个BETWEEN其中包括两个较低的值,并在范围的上限的值,但并不神奇地让一个日期或者"结束""的开始".

BETWEEN 按日期范围过滤时应避免使用.

总是>= AND <而不是

SELECT * FROM Cases 
WHERE (created_at >= '20130501' AND created_at < '20130502')

括号在这里是可选的,但在更复杂的查询中可能很重要.

  • 致编辑; 请不要尝试将伪SQL变成代码块,它根本不起作用,因为注释依赖于BOLD. (5认同)
  • 不确定在问题已经回答后能否很好地发布,但是我想强调一点不同的地方 (2认同)
  • 再次(对于)编辑,请勿通过伪代码添加虚假的引号;他们不帮助理解。 (2认同)

Bar*_*nka 16

您需要执行以下两个选项之一:

  1. 在您的between条件中包含时间组件:( ... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59'不推荐...参见最后一段)
  2. 使用不等式代替between.请注意,那么您必须在第二个值中添加一天:... where (created_at >= '2013-05-01' and created_at < '2013-05-02')

我个人的偏好是第二种选择.此外,Aaron Bertrand对为何应该使用它有一个非常明确的解释.

  • +1为2.但-1为1.这一天结束黑客是完全不可靠和一个坏主意. (6认同)
  • [请完整阅读](http://sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/what-do-between-and-the-devil-have-in-common.aspx).对于包含时间的日期范围查询,您永远不应该使用"BETWEEN"; 方式太多可能会出错. (5认同)

Bal*_*nti 6

只需将时间戳记用作日期:

SELECT * FROM Cases WHERE date(created_at)='2013-05-01' 
Run Code Online (Sandbox Code Playgroud)

  • 问题被标记为SQL Server,并且'DATE'不是公认的内置函数名称。`需要转换http://stackoverflow.com/a/20973452/4233593 (4认同)

小智 6

我发现将datetime字段与date字段进行比较的最佳解决方案是:

DECLARE @StartDate DATE = '5/1/2013', 
        @EndDate   DATE = '5/1/2013' 

SELECT * 
FROM   cases 
WHERE  Datediff(day, created_at, @StartDate) <= 0 
       AND Datediff(day, created_at, @EndDate) >= 0 
Run Code Online (Sandbox Code Playgroud)

这等效于包含之间的语句,因为它既包含开始日期也包含结束日期以及介于两者之间的日期。