我正在尝试在SQL查询中比较日期时间字段中的时间,但我不知道它是否正确。我不想比较日期部分,只是时间部分。
我这样做:
SELECT timeEvent
FROM tbEvents
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8)
这是对的吗?
我问这个是因为我需要知道08:00:00
是否小于或大于07:30:00
并且我不想比较日期,只需时间一部分。
谢谢!
答案 0 :(得分:74)
您的比较将起作用,但它会很慢,因为日期会转换为每行的字符串。要有效地比较两个时间部分,请尝试:
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 Server中的日期存储为浮点数。小数点前的数字代表日期。小数点后面的数字代表时间。
所以这是一个例子日期:
declare @mydate datetime
set @mydate = '2009-04-30 19:47:16.123'
让我们将其转换为浮动:
declare @myfloat float
set @myfloat = cast(@mydate as float)
select @myfloat
-- Shows 39931,8244921682
现在取数字之后的部分,即时间:
set @myfloat = @myfloat - floor(@myfloat)
select @myfloat
-- Shows 0,824492168212601
将其转换回日期时间:
declare @mytime datetime
set @mytime = convert(datetime,@myfloat)
select @mytime
-- Shows 1900-01-01 19:47:16.123
1900-01-01只是“零”日期;你可以用转换显示时间部分,例如指定格式108,这就是时间:
select convert(varchar(32),@mytime,108)
-- Shows 19:47:16
datetime和float之间的转换非常快,因为它们基本上以相同的方式存储。
答案 1 :(得分:18)
convert(varchar(5), thedate, 108) between @leftTime and @rightTime
说明:
如果您有varchar(5)
,您将获得HH:mm
如果您varchar(8)
获得HH:mm ss
108只获取SQL日期的时间
@leftTime
和@rightTime
是两个要比较的变量
答案 2 :(得分:11)
如果您使用的是SQL Server 2008,则可以执行以下操作:
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)
这是一个完整的测试:
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)
答案 3 :(得分:4)
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))
答案 4 :(得分:3)
只需将转换日期时间更改为应该执行操作的时间:
SELECT timeEvent
FROM tbEvents
WHERE convert(time, startHour) >= convert(time, @startHour)
答案 5 :(得分:3)
到目前为止我在解决方案中注意到的一个(可能很小的)问题是它们似乎都需要函数调用来处理比较。这意味着查询引擎将需要执行全表扫描以查找您之后的行 - 并且无法使用索引。如果表格不会变得特别大,这可能不会产生任何不利影响(你可以高兴地忽略这个答案)。
另一方面,如果表格变得非常大,查询的性能可能会受到影响。
我知道您声明您不希望比较日期部分 - 但是实际日期是存储在日期时间列中,还是您使用它来存储时间?如果是后者,您可以使用简单的比较运算符,这将减少CPU使用率,并允许查询引擎使用统计信息和索引(如果存在)来优化查询。
但是,如果使用datetime列来存储事件的日期和时间,这显然不起作用。在这种情况下,如果您可以修改应用程序和表结构,请将日期和时间分成两个单独的日期时间列,或者创建一个索引视图,选择源表的所有(相关)列,以及另一个包含该列的列。您希望搜索的时间元素(使用以前的任何答案来计算) - 并改变应用程序以查询视图。
答案 6 :(得分:3)
使用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之间的当前时间。
答案 7 :(得分:2)
使用Datepart函数:DATEPART(datepart,date)
E.g#
SELECT DatePart(@YourVar,hh)* 60)+ DatePart(@YourVar,mi)* 60)
这将为您提供以分钟为单位的总时间,让您更轻松地进行比较。
如果您的日期相同,您可以使用DateDiff,否则您需要删除上述日期
答案 8 :(得分:2)
添加其他答案:
您可以创建一个从日期时间修剪日期的功能
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
答案 9 :(得分:2)
您可以创建两个datetime变量,并且只设置您需要比较的日期小时。
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)
日期将是“1900-01-01”,你可以比较它
if @date1 <= @date2
print '@date1 less then @date2'
else
print '@date1 more then @date2'
答案 10 :(得分:1)
SELECT timeEvent
FROM tbEvents
WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'
这告诉SQL Server使用样式108将当前日期/时间转换为varchar,即“hh:mm:ss”。您也可以替换'01:01:01',如果需要,可以替换另一个。
答案 11 :(得分:1)
我不喜欢依赖存储内部(日期时间是一个浮点数,整数=天和小数=时间),但我做的答案与答案Jhonny D. Cano相同。这就是我所知道的所有db开发者的方式。绝对不要转换为字符串。如果你必须避免处理float / int,那么最好的选择是使用DatePart()拉出小时/分钟/秒/毫秒
答案 12 :(得分:1)
答案 13 :(得分:0)
答案 14 :(得分:0)
我假设您的startHour列和@startHour变量都是DATETIME;在这种情况下,您应该转换为字符串:
SELECT timeEvent
FROM tbEvents
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8)
答案 15 :(得分:0)
@ronmurp提出了一个有效的问题 - 演员/场地方法同时返回不同的值。根据@littlechris的回答以及一个更通用的解决方案来解决具有分钟,秒,毫秒组件的时间,您可以使用此函数来计算从一天开始的毫秒数。
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
我已经验证它在两个不同日期以相同的时间返回相同的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 )
此解决方案并不总是返回您期望的int。例如,在SQL 2005中尝试以下操作,它返回一个以'557'结尾的int而不是'556'。
set @first = '1900-01-01 23:59:39.556'
set @second = '2000-11-02 23:56:39.556'
我认为这与存储为float的DateTime的性质有关。不过,您仍然可以比较这两个数字。当我在使用DateTime.Now()在.NET中捕获的DateTime的“真实”数据集上使用这种方法并存储在SQL中时,我发现计算是准确的。
答案 16 :(得分:0)
如果要在搜索中使用索引,则将时间值与日期值分开(为提高性能,可能应该这样做)。您可以:(1)使用基于函数的索引,或者(2)仅为时间创建一个新列,对该列进行索引并在您的SELECT
子句中使用它。
请紧记,如果您在SQL的WHERE
子句中使用函数,您将失去任何索引性能的提升,引擎必须执行扫描搜索。只需使用EXPLAIN SELECT...
运行查询即可确认。发生这种情况是因为引擎必须在字段中处理每个值以进行每次比较,并且转换后的值未编制索引。
大多数答案都说使用float()
,convert()
,cast()
,addtime()
等。同样,如果您这样做,数据库将不使用索引。对于小桌子可能没问题。
尽管可以在WHERE
参数中使用函数(where field = func(value)
),因为您不会在表中更改每个字段的值。
如果要继续使用索引,可以为时间值创建基于函数的索引。正确的方法(及其支持)可能取决于您的数据库引擎。另一种选择是添加一列以仅存储时间值并为此列编制索引,但是请首先尝试使用前一种方法。
在将数据库更新为具有新的时间列或使用索引的任何内容之前,请进行一些性能测试。在我的测试中,我发现性能提升很小(当我可以看到有所改善时),并且不值得添加新索引带来的麻烦和开销。