我如何比较SQL Server中的时间?
我试图在SQL查询中的date时间字段比较时间,但我不知道它是正确的。 我不想比较date部分,只是时间部分。
我正在这样做:
SELECT timeEvent FROM tbEvents WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8)
这是对的吗?
我问这是因为我需要知道'08:00:00'是小于还是大于'07:30:00',我不想比较date,只是时间部分。
谢谢!
您的比较可以正常工作,但会比较慢,因为date会转换为每行的string。 要有效比较两个时间部分,请尝试:
declare @first datetime set @first = '2009-04-30 19:47:16.123' declare @second datetime set @second = '2009-04-10 19:47:16.123' select (cast(@first as float) - floor(cast(@first as float))) - (cast(@second as float) - floor(cast(@second as float))) as Difference
详细解释:SQL服务器中的date存储为浮点数。 小数点前的数字表示date。 小数点后面的数字代表时间。
所以这是一个例子date:
declare @mydate datetime set @mydate = '2009-04-30 19:47:16.123'
让我们把它转换成一个float:
declare @myfloat float set @myfloat = cast(@mydate as float) select @myfloat -- Shows 39931,8244921682
现在采取数字后的部分,即时间:
set @myfloat = @myfloat - floor(@myfloat) select @myfloat -- Shows 0,824492168212601
将其转换回date时间:
declare @mytime datetime set @mytime = convert(datetime,@myfloat) select @mytime -- Shows 1900-01-01 19:47:16.123
1900-01-01只是“零”date; 你可以显示转换的时间部分,例如指定格式108,这只是时间:
select convert(varchar(32),@mytime,108) -- Shows 19:47:16
datetime和float之间的转换非常快,因为它们基本上是以相同的方式存储的。
convert(varchar(5), thedate, 108) between @leftTime and @rightTime
说明:
如果你有varchar(5)
你会得到HH:mm
如果你有varchar(8)
你会得到HH:mm ss
108仅从SQLdate获得时间
@leftTime
和@rightTime
是两个variables进行比较
如果你使用SQL Server 2008,你可以这样做:
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)
这是一个完整的testing:
DECLARE @tbEvents TABLE ( timeEvent int IDENTITY, startHour datetime ) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 0, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 1, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 2, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 3, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 4, GETDATE()) INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 5, GETDATE()) --SELECT * FROM @tbEvents DECLARE @startTime datetime SET @startTime = DATEADD(mi, 65, GETDATE()) SELECT timeEvent, CONVERT(time(0), startHour) AS 'startHour', CONVERT(time(0), @startTime) AS '@startTime' FROM @tbEvents WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)
if (cast('2012-06-20 23:49:14.363' as time) between cast('2012-06-20 23:49:14.363' as time) and cast('2012-06-20 23:49:14.363' as time))
到目前为止,我已经注意到的一个(可能很小的)问题是它们似乎都需要一个函数调用来处理比较。 这意味着查询引擎将需要执行全表扫描以查找之后的行,并且无法使用索引。 如果表格不会特别大,这可能不会有任何不利的影响(你可以高兴地忽略这个答案)。
另一方面,如果表格可能变得相当大,则查询的性能可能受损。
我知道你说过,你不希望比较date部分 – 但有一个实际的date被存储在date时间列,或者你用它来存储只有时间? 如果是后者,则可以使用简单的比较运算符,这将减lessCPU使用率,并允许查询引擎使用统计信息和索引(如果存在)来优化查询。
但是,如果使用datetime列来存储事件的date和时间,这显然不起作用。 在这种情况下,如果您可以修改应用程序和表结构,请将date和时间分隔为两个单独的date时间列,或者创build一个索引视图,用于select源表的所有(相关)列,另一列包含(使用任何以前的答案来计算这个),并改变应用程序来查询视图。
使用float不起作用。
DECLARE @t1 datetime, @t2 datetime SELECT @t1 = '19000101 23:55:00', @t2 = '20001102 23:55:00' SELECT CAST(@t1 as float) - floor(CAST(@t1 as float)), CAST(@t2 as float) - floor(CAST(@t2 as float))
你会看到这些值是不一样的(SQL Server 2005)。 我想用这种方法来检查午夜的时间(完整的方法有更多的细节),我在比较当前时间是23:55:00和00:05:00之间。
添加到其他答案:
您可以创build一个从date时间修剪date的函数
CREATE FUNCTION dbo.f_trimdate (@dat datetime) RETURNS DATETIME AS BEGIN RETURN CONVERT(DATETIME, CONVERT(FLOAT, @dat) - CONVERT(INT, @dat)) END
所以这:
DECLARE @dat DATETIME SELECT @dat = '20080201 02:25:46.000' SELECT dbo.f_trimdate(@dat)
将返回1900-01-01 02:25:46.000
使用date部分function: DATEPART (date部分,date)
例如#
SELECT DatePart(@YourVar,hh)* 60)+ DatePart(@YourVar,mi)* 60)
这会给你一分钟的总时间,让你更容易比较。
如果你的date是一样的,你可以使用DateDiff,否则你需要去掉上面的date
只要改变转换date时间,应该做的伎俩:
SELECT timeEvent FROM tbEvents WHERE convert(time, startHour) >= convert(time, @startHour)
我不喜欢依靠存储内部(那个date时间是一个整数=date和分数=时间的浮点数),但是我的答案与Jhonny D. Cano相同。 这就是我所知道的所有数据库开发人员所做的工作。 绝对不要转换为string。 如果您必须避免处理为float / int,那么最好的select是用DatePart()函数抽出小时/分钟/秒/毫秒
你可以创build一个datetime的两个variables,并且只设置需要比较的date。
declare @date1 datetime; declare @date2 datetime; select @date1 = CONVERT(varchar(20),CONVERT(datetime, '2011-02-11 08:00:00'), 114) select @date2 = CONVERT(varchar(20),GETDATE(), 114)
date将是“1900-01-01”,你可以比较它
if @date1 <= @date2 print '@date1 less then @date2' else print '@date1 more then @date2'
SELECT timeEvent FROM tbEvents WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'
这告诉SQL Server使用样式108(“hh:mm:ss”)将当前date/时间转换为varchar。 您也可以replace“01:01:01”,如果需要的话另外进行转换。
我假设你的startHour列和@startHourvariables都是DATETIME; 在这种情况下,你应该转换成一个string:
SELECT timeEvent FROM tbEvents WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8)
下面的查询给你的时间的date
select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table
@ronmurp提出了一个有效的关注点 – 演员/场地方法在同一时间返回不同的值。 沿着@littlechris回答的路线,为了解决具有分,秒,毫秒组件时间的更一般的解决scheme,可以使用此函数来计算从一天开始的毫秒数。
Create Function [dbo].[MsFromStartOfDay] ( @DateTime datetime ) Returns int As Begin Return ( ( Datepart( ms , @DateTime ) ) + ( Datepart( ss , @DateTime ) * 1000 ) + ( Datepart( mi , @DateTime ) * 1000 * 60 ) + ( Datepart( hh , @DateTime ) * 1000 * 60 * 60 ) ) End
我已经validation它在同一时间返回两个不同date的相同的int
declare @first datetime set @first = '1900-01-01 23:59:39.090' declare @second datetime set @second = '2000-11-02 23:56:39.090' Select dbo.MsFromStartOfDay( @first ) Select dbo.MsFromStartOfDay( @second )
这个解决scheme并不总是返回你所期望的int。 例如,在SQL 2005中尝试下面的代码,它将返回一个以'557'结尾而不是'556'结尾的int。
set @first = '1900-01-01 23:59:39.556' set @second = '2000-11-02 23:56:39.556'
我认为这与以floatforms存储的DateTime的性质有关。 不过,你仍然可以比较两个数字。 当我在DateTime.Now()中使用DateTime.Now()捕获的“真实”数据集上使用这种方法时,我发现计算是准确的。