在SQL Server中删除datetime的时间部分的最佳方法

在SQL Server中从datetime字段中删除时间部分时,哪种方法提供了最佳性能?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

b) select cast(convert(char(11), getdate(), 113) as datetime)

第二种方法确实发送了更多的字节,但这可能没有转换速度那么重要。

两者看起来也都非常快,但在处理数十万行或更多行的时候,速度可能会有所不同。

此外,是否可能有更好的方法来消除SQL中datetime的时间部分?

928679 次浏览

把插入/更新的时间放在首位。至于动态转换,没有什么能比得上用户定义函数的可维护性:

select date_only(dd)

date_only的实现可以是你喜欢的任何东西——现在它被抽象了,调用代码变得非常非常干净。

SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)

...根据下面的评论,是一个很好的解决方案。

我想删除这个答案,但我把它留在这里作为一个反例,因为我认为评论者对为什么不是一个好主意的解释仍然有用。

就我个人而言,如果处理SQL Server 2005(或更低版本),几乎总是使用用户定义函数,然而,应该注意的是,使用UDF有特定的缺点,特别是如果将它们应用于WHERE子句(参见下面和对这个答案的评论了解更多细节)。如果使用SQL Server 2008(或更高版本)-请参见下面。

事实上,对于我创建的大多数数据库,我都是在一开始就添加这些UDF,因为我知道早晚有99%的可能性会用到它们。

我创建了一个“仅限约会”&“仅限时间”(尽管“仅限日期”是迄今为止使用最多的一个)。

以下是一些与日期相关的UDF的链接:

< p > # EYZ0 < br > # EYZ0 < / p >

最后一个链接显示了不少于3种获取datetime字段部分日期的不同方法,并提到了每种方法的优缺点。

如果使用UDF,应该注意,应该尽量避免将UDF用作查询中的WHERE子句的一部分,因为这将极大地影响查询的性能。主要原因是在WHERE子句中使用UDF会将该子句呈现为non-sargable,这意味着SQL Server不能再使用该子句的索引来提高查询执行的速度。参考我自己对UDF的使用,我将经常在WHERE子句中使用“原始”日期列,但将UDF应用于SELECTed列。这样,UDF仅应用于过滤后的结果集,而不是作为过滤器的一部分应用于表的每一行。

当然,绝对的最好的方法是使用SQL Server 2008(或更高版本)并分离出日期和时间,因为SQL Server数据库引擎随后本地提供了单独的日期和时间组件,并且可以有效地独立查询这些组件,而不需要UDF或其他机制来从复合datetime类型中提取日期或时间部分。

严格来说,方法a是资源密集度最低的:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

对于那些手头上有太多时间的人来说,在相同的总持续时间下,更少的CPU密集型:在SQL Server中最有效的方法从日期+时间获得日期?

我在其他地方看到了类似的测试,结果也类似。

我更喜欢DATEADD/DATEDIFF,因为:

  • varchar受语言/日期格式问题的影响
    例子:# EYZ0李< / >
  • Float依赖于内部存储
  • 它延伸到工作的第一天,明天,等通过改变“;0"基地

编辑,2011年10月

对于SQL Server 2008+,您可以CAST到date,即CAST(getdate() AS date)。或者只是使用date数据类型,所以没有time删除。

编辑,2012年1月

关于这有多灵活的一个工作示例:需要在sql server中按四舍五入的时间或日期图计算

编辑,2012年5月

不要在WHERE子句和类似的地方使用这个:向列添加函数或CAST会使索引使用无效。请看第2条SQL编程常见错误

现在,这确实有一个例子,后来的SQL Server优化器版本管理CAST的日期正确,但一般这将是一个坏主意…

编辑,2018年9月,datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'


select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)

请看这个问题:
# EYZ0 < / p >

不管你做什么,不要使用字符串方法。这是最糟糕的方法了。

这里还有另一个答案,来自另一个重复的问题:

SELECT CAST(CAST(getutcdate() - 0.50000004 AS int) AS datetime)

这个魔数方法比DATEADD方法执行得稍微快一些。(看起来像~10%)

百万记录数轮的CPU时间:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

但请注意,这些数字可能无关紧要,因为它们已经非常快了。除非我有100,000或更多的记录集,否则我甚至无法让CPU时间读数高于零。

考虑到DateAdd就是为了这个目的,而且更健壮,我建议使用DateAdd。

已经回答了,但我也要把这个放在那里… 这应该也表现得很好,但它的工作原理是从浮点数中丢弃小数(存储时间),只返回整部分(即date)

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

我第二次找到这个解决方案…# EYZ0

如果可能的话,对于这样的特殊情况,我喜欢使用CLR函数。

在这种情况下:

[Microsoft.SqlServer.Server.SqlFunction]
public static SqlDateTime DateOnly(SqlDateTime input)
{
if (!input.IsNull)
{
SqlDateTime dt = new SqlDateTime(input.Value.Year, input.Value.Month, input.Value.Day, 0, 0, 0);


return dt;
}
else
return SqlDateTime.Null;
}
CAST(round(cast(getdate()as real),0,1) AS datetime)

此方法不使用字符串函数。Date基本上是一个真实的数据类型,十进制前的数字是一天的小数。

我猜这个会比很多快。

我想你的意思是 # EYZ0 < / p >

Real只有32位,可能会丢失一些信息

这是最快的 # EYZ0 < / p >

...虽然只快了10% (about 0.49 microseconds CPU vs. 0.58)

这是推荐的,在我刚才的测试中需要相同的时间: # EYZ0 < / p >

在SQL 2008中,SQL CLR函数比使用SQL函数快5倍,1.35微秒比6.5微节,这表明SQL CLR函数比简单的SQL UDF函数调用开销要低得多。

在SQL 2005中,根据我的测试,SQL CLR函数比这个慢函数快16倍:

create function dateonly (  @dt datetime )
returns datetime
as
begin
return cast(floor(cast(@dt as float))as int)
end

当然,这是一个旧的线程,但使它完整。

从SQL 2008你可以使用DATE数据类型,所以你可以简单地做:

SELECT CONVERT(DATE,GETDATE())

对我来说,下面的代码总是一个赢家:

SELECT CONVERT(DATETIME, FLOOR(CONVERT(FLOAT,GETDATE())));
SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)

我认为如果你严格地使用TSQL,这是截断时间的最快方法:

 select convert(datetime,convert(int,convert(float,[Modified])))

我发现这种截断方法比DateAdd方法快5%左右。这可以很容易地修改为四舍五入到最近的一天,像这样:

select convert(datetime,ROUND(convert(float,[Modified]),0))

在SQL Server 2008中,您可以使用:

CONVERT(DATE, getdate(), 101)

我会用:

CAST
(
CAST(YEAR(DATEFIELD) as varchar(4)) + '/' CAST(MM(DATEFIELD) as varchar(2)) + '/' CAST(DD(DATEFIELD) as varchar(2)) as datetime
)

因此,有效地从已有的日期字段创建一个新字段。

小心!

方法a)和b)并不总是有相同的输出!

select DATEADD(dd, DATEDIFF(dd, 0, '2013-12-31 23:59:59.999'), 0)

输出:# EYZ0

select cast(convert(char(11), '2013-12-31 23:59:59.999', 113) as datetime)

输出:# EYZ0

(在MS SQL Server 2005和2008 R2上测试)

编辑:根据Adam的评论,如果从表中读取日期值,则不会发生这种情况,但如果将日期值作为文本提供(例如:作为通过ADO.NET调用的存储过程的参数),则会发生这种情况。

select CONVERT(char(10), GetDate(),126)

select cast(cast my_datetime_field as date) as datetime)怎么样?结果是相同的日期,时间设置为00:00,但避免了任何文本转换,也避免了任何显式的数字舍入。

在SQL Server 2008中,有一个DATE数据类型(也是一个TIME数据类型)。

CAST(GetDate() as DATE)

declare @Dt as DATE = GetDate()

以防有人在这里寻找一个Sybase版本,因为上面的几个版本都不能工作

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • 在Adaptive Server 15.7上运行的I SQL v11中测试

在这里,我做了一个函数来删除SQL Server的日期时间的某些部分。用法:

  • 第一个参数是要剥离的datetime。
  • 第二个参数为char类型:
    • S:转到秒;删除毫秒
    • M:数到分钟;删除秒和毫秒
    • H:转到小时;删除分钟、秒和毫秒。
    • D:轮到天;删除小时、分钟、秒和毫秒。
    • 李< / ul > < / >
    • 返回新的日期时间

    创建函数dbo。uf_RoundDateTime(@dt作为datetime, @part作为char) 返回日期时间 作为 开始 如果CHARINDEX(@part, 'smhd',0) = 0返回@dt; 返回演员( 案例@part 当's'时,convert(varchar(19), @dt, 126) 当'm'时,则convert(varchar(17), @dt, 126) + '00' 当'h'时,则convert(varchar(14), @dt, 126) + '00:00' 当'd'时,convert(varchar(14), @dt, 112) 结束为datetime) 结束代码< / > < / p >

我非常喜欢:

[date] = CONVERT(VARCHAR(10), GETDATE(), 120)

120格式代码将强制将日期转换为ISO 8601标准:

'YYYY-MM-DD' or '2017-01-09'

超级容易在dplyr (R)和pandas (Python)中使用!