SQL“之间”不包括在内
Posted
技术标签:
【中文标题】SQL“之间”不包括在内【英文标题】:SQL "between" not inclusive 【发布时间】:2013-04-27 04:36:58 【问题描述】:我有一个这样的查询:
SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'
但是即使1号有数据,这也没有结果。
created_at
看起来像2013-05-01 22:25:19
,我怀疑它与时间有关?如何解决?
如果我做更大的日期范围,它工作得很好,但它应该(包括)也适用于单个日期。
【问题讨论】:
那么,1 和 1 之间有多少个数字? 1.5 应该在 1 和 1 之间吗? Just don't use BETWEEN for date/time ranges. Ever. 并且要小心你如何评估“工作正常”——你是否仔细检查了该范围内最后一天的结果?如果它们没有任何时间与它们相关联,您将只包括所有行。 更新了 Aaron 的 URL:sqlblog.org/2011/10/19/… 【参考方案1】:你的代码
SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'
SQL 如何读取它
SELECT * FROM Cases WHERE '2013-05-01 22:25:19' BETWEEN '2013-05-01 00:00:00' AND '2013-05-01 00:00:00'
如果您在比较 DateTime 和 Date 时未提及时间,默认时时:分:秒在您的情况下将为零,日期相同,但如果您比较时间 created_at
是在结束日期范围之前的 22 hours
如果上述内容很清楚,您可以通过多种方式解决此问题,例如将结束时间放在结束日期中,例如 BETWEEN '2013-05-01' AND ''2013-05-01 23:59:59''
或
在转换为日期'2013-05-01 22:25:19'
之后将create_at 转换为cast(created_at as date)
这样的日期将等于'2013-05-01 00:00:00'
【讨论】:
【参考方案2】:sql查询之间的动态日期
var startDate = '2019-08-22';
var Enddate = '2019-10-22'
let sql = "SELECT * FROM Cases WHERE created_at BETWEEN '?' AND '?'";
const users = await mysql.query( sql, [startDate, Enddate]);
【讨论】:
【参考方案3】:您需要执行以下两个选项之一:
-
在
between
条件中包含时间组件:... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59'
(不推荐...见最后一段)
使用不等式代替between
。请注意,您必须将一天添加到第二个值:... where (created_at >= '2013-05-01' and created_at < '2013-05-02')
我个人的偏好是第二个选项。另外,Aaron Bertrand 有 a very clear explanation on why 应该使用。
【讨论】:
+1 表示 2。但 -1 表示 1。这种结束一天的黑客攻击完全不可靠,而且是个坏主意。 @AaronBertrand 我也更喜欢选项 2(我经常使用它)。但是为什么你说选项 1“完全不可靠”呢? please read this in full。对于包含时间的日期范围查询,您永远不应该使用BETWEEN
;太多可能会出错。
虽然 2. 有效,但我将始终将其写为 where ('2013-05-01' <= created_at and created_at <= '2013-05-01')
以提高可读性【参考方案4】:
它是包容性的。您正在将日期时间与日期进行比较。第二个日期被解释为当天开始时的午夜。
解决此问题的一种方法是:
SELECT *
FROM Cases
WHERE cast(created_at as date) BETWEEN '2013-05-01' AND '2013-05-01'
另一种解决方法是显式二进制比较
SELECT *
FROM Cases
WHERE created_at >= '2013-05-01' AND created_at < '2013-05-02'
Aaron Bertrand 有一篇关于日期的长博客文章 (here),他在其中讨论了这个和其他日期问题。
【讨论】:
为了这个好答案的完整性,我建议使用dateadd
来获得第二天。
@TimLehner 为了得到一个好的答案,我会使用“20130501”的 ISO-8601 格式。对于使用 dateformat dmy 的非美国人,你会得到这个:set dateformat dmy;select month(cast('2013-05-01' as datetime)); =1
@RichardTheKiwi - 我相信 explicit 位正在使用一个在一端关闭的间隔 (>=
) 在另一端打开 (<
) 并结合检查一个指定结束日期之后的一天。
@scottb 就我个人而言,每次我想显示、导出、导入或编写带有日期时间的类时,我都会觉得很烦人。我认为 SQL Server 有很多内置功能可以在大多数情况下操作和比较日期时间。
您永远不应该在where
子句中强制转换列,因为它会丢失它拥有的任何索引。这是一个非常糟糕的模式。【参考方案5】:
我发现将日期时间字段与日期字段进行比较的最佳解决方案如下:
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
这相当于一个包含的 between 语句,因为它包括开始日期和结束日期以及介于两者之间的日期。
【讨论】:
【参考方案6】:您可以使用date()
函数从日期时间中提取日期并将结果作为包含日期提供给您:
SELECT * FROM Cases WHERE date(created_at)='2013-05-01' AND '2013-05-01'
【讨论】:
【参考方案7】:假设BETWEEN
语法中的第二个日期引用被神奇地认为是“一天的结束”,但这是不正确的。
即这是意料之中的:
从案例中选择 * WHERE created_at BETWEEN 开始'2013-05-01'和结束'2013-05- 01'但真正发生的是:
从案例中选择 * 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 <
括号在这里是可选的,但在更复杂的查询中可能很重要。
【讨论】:
在问题已经得到解答后,不确定发布此内容是否明智,但我想强调一点不同 致编辑;请不要尝试将伪 SQL 制作成代码块,因为注释依赖 BOLD,它根本不起作用。 请各位编辑(再次)不要通过伪代码添加虚假引号;他们不帮助理解。【参考方案8】:只需使用时间戳作为日期:
SELECT * FROM Cases WHERE date(created_at)='2013-05-01'
【讨论】:
问题标记为SQL Server,而'DATE' is not a recognized built-in function name.
需要转换***.com/a/20973452/4233593
? 它有效!!!!拯救我的一天?【参考方案9】:
cast(created_at as date)
这仅适用于 2008 年和更新版本的 SQL Server
如果您使用的是旧版本,请使用
convert(varchar, created_at, 101)
【讨论】:
convert(varchar, created_at, 101)
结果就像dd/MM/yyyy
并且OP的字符串是yyyy-MM-dd
,我认为这个答案行不通;)。以上是关于SQL“之间”不包括在内的主要内容,如果未能解决你的问题,请参考以下文章