如何在 TIME 数据类型上应用 SQL 'between' 关键字
Posted
技术标签:
【中文标题】如何在 TIME 数据类型上应用 SQL \'between\' 关键字【英文标题】:How to apply SQL 'between' keyword on TIME data type如何在 TIME 数据类型上应用 SQL 'between' 关键字 【发布时间】:2014-01-10 14:29:50 【问题描述】:--我想在 TIME 数据类型上使用 SQL - BETWEEN
。
我想执行下面的查询,但它没有给出正确的结果。
在这里,starttime
和 endtime
两个字段都是 typeof smalldatetime
,因为我只需要时间比较并且日期的值不是实际的,它只是虚拟的,因此我将其转换为 TIME 字段。
SELECT
count(1)
FROM
t1 INNER JOIN t2
WHERE
CAST(t1.StartTime as TIME)
BETWEEN CAST(t2.StartTime as TIME)
AND CAST(t2.EndTime as TIME)
CAST(t1.StartTime as TIME) is 08:00:00.0000000
CAST(t2.StartTime as TIME) is 07:00:00.0000000
CAST(t2.StartTime as TIME) is 12:00:00.0000000
所以,上面的查询结果应该是记录计数 1(因为 8 点钟在 7 到 12 之间)。但它返回 null。
请告诉我这里有什么问题以及如何纠正。
谢谢
【问题讨论】:
您能否提供示例数据和结果以便我们查看问题? 你的意思是 SELECT COUNT(*) 吗? 在处理像时间这样的连续数据时,通常最好使用半开区间,例如>= start time AND < end time
而不是使用BETWEEN
。它往往会导致更自然的查询(例如,如果您运行一个关于早上的查询,然后是一个关于下午的查询,您倾向于希望恰好在中午发生的事件只出现在其中一个查询的结果中,而不是比两者都)
【参考方案1】:
WHERE CAST(t1.StartTime as TIME) >= CAST(t2.StartTime as TIME)
AND CAST(t1.StartTime as TIME) <= CAST(t2.EndTime as TIME)
使用此 Snytax 可以使您的查询 SARGable。 Read Here 了解有关在使用日期时间/日期/时间数据类型时使您的查询可查询的更多信息。
【讨论】:
BETWEEN
也是 sargable (您的查询是没有该关键字的 BETWEEN
,就像 WHILE
循环仍然是没有 CURSOR
关键字的 CURSOR
。也许 the problem with BETWEEN
is slightly misunderstood .
另外,在个别情况下,列上的CAST
仍然是可搜索的(根本没有很多),还有other potential problems。
@AaronBertrand 感谢您指出这一点并提供有用的链接。
@AaronBertrand 在阅读了您标题为 What do BETWEEN and the devil have in common?
的文章后,我已停止使用 BETWEEN 作为日期日期
我知道,我在评论您说“使用此语法使您的查询 SARGable”,但实际上这个查询并不比使用 BETWEEN 的等效查询更 SARGable。 BETWEEN 的问题在于大多数人不了解边界(并且大多数查询并不真正想要两个帖子 - 例如,2 月 1 日和 3 月 1 日之间的数据包括 3 月 1 日午夜的数据,而 2 月 1 日和 2 月 28 日之间的数据仅包括数据从 2 月 28 日午夜开始,但不是从凌晨 1 点、中午、晚上 8 点等开始)。【参考方案2】:
between 的语法是正确的。您需要指定联接并提供这样的on
子句:
SELECT count(1) FROM t1 INNER JOIN t2 on t1.col = t2.col
WHERE CAST(t1.StartTime as TIME) BETWEEN CAST(t2.StartTime as TIME) AND CAST(t2.EndTime as TIME)
【讨论】:
【参考方案3】:我怀疑根据您的示例,您正在寻找 t1 中的时间,介于 t2 的开始时间和结束时间之间,但是这两个表不一定在任何键上都有关系。
尝试在这种情况下使用连接并不容易,您必须将 M. Ali 的解决方案移至连接谓词而不是 where 条件。
如果我的假设是正确的,并且您只是在 t2 中寻找与您的 between 条件匹配的 t1 行,那么这应该会让您在没有两个表有关系的情况下获得该设置:
DECLARE @sampleTime AS smalldatetime = GETDATE()
CREATE TABLE #t1 (StartTime smalldatetime)
CREATE TABLE #t2 (StartTime smalldatetime, EndTime smalldatetime)
INSERT INTO #t1 (StartTime) VALUES (@sampleTime)
INSERT INTO #t1 (StartTime) VALUES (DATEADD(hh, 6, @sampleTime))
INSERT INTO #t2 (StartTime, EndTime) VALUES (DATEADD(hh, -1, @sampleTime), DATEADD(hh, 3, @sampleTime))
-- you can see only one row in t1 lands between the Start and End in t2
SELECT * FROM #t1
WHERE EXISTS(SELECT * FROM #t2 WHERE CAST(#t1.StartTime AS time) BETWEEN CAST(#t2.StartTime AS time) AND CAST(#t2.EndTime AS time))
-- adding another row to t1 that now lands between the Start and End in t2 and the result
INSERT INTO #t1 (StartTime) VALUES (DATEADD(hh, 1, @sampleTime))
SELECT * FROM #t1
WHERE EXISTS(SELECT * FROM #t2 WHERE CAST(#t1.StartTime AS time) BETWEEN CAST(#t2.StartTime AS time) AND CAST(#t2.EndTime AS time))
DROP TABLE #t1, #t2
【讨论】:
以上是关于如何在 TIME 数据类型上应用 SQL 'between' 关键字的主要内容,如果未能解决你的问题,请参考以下文章
sql 中 timestamp 类型的时间 作为条件 如何进行查询
在mysql中怎么插入一个time类型的数据,数据库字段的数据类型是time,我后台要插入数据 String sql="insert