如何在SQL Server中截断日期时间?

Jul*_*sar 265 sql-server datetime truncate sql-server-2008

在SQL Server 2008中截断日期时间值(删除小时分钟和秒)的最佳方法是什么?

例如:

declare @SomeDate datetime = '2009-05-28 16:30:22'
select trunc_date(@SomeDate)

-----------------------
2009-05-28 00:00:00.000
Run Code Online (Sandbox Code Playgroud)

Joe*_*orn 471

这继续经常收集额外的投票,甚至几年后,所以我需要为现代版本的Sql Server更新它.对于Sql Server 2008及更高版本,它很简单:

cast(getDate() As Date)
Run Code Online (Sandbox Code Playgroud)

请注意,底部附近的最后三段仍然适用,您通常需要退后一步,找到一种方法来避免演员阵容.

但也有其他方法可以实现这一目标.这是最常见的.

正确的方法(自Sql Server 2008以来的新方法):

cast(getdate() As Date)
Run Code Online (Sandbox Code Playgroud)

正确的方法(旧):

dateadd(dd, datediff(dd,0, getDate()), 0)
Run Code Online (Sandbox Code Playgroud)

这个现在已经老了,但它仍然值得知道,因为它也可以很容易地适应其他时间点,比如月,分,小时或年的第一个时刻.

这种正确的方法使用了作为ansi标准一部分的文档化函数,并保证可以正常工作,但它可能会慢一些.它的工作原理是查找从第0天到当天的天数,并将这几天添加到第0天.无论您的日期时间是如何存储的,无论您的语言环境如何,它都能正常工作.

快捷方式:

cast(floor(cast(getdate() as float)) as datetime)
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为datetime列存储为8字节二进制值.将它们转换为浮动,将它们放置以移除分数,并且当您将它们转换回日期时间时,值的时间部分将消失.它只是位移,没有复杂的逻辑,而且速度非常快.

请注意,这依赖于实现细节Microsoft可以随时更改,即使在自动服务更新中也是如此.它也不是很便携.在实践中,这种实施很可能不会很快改变,但是如果你选择使用它,那么了解危险仍然很重要.现在我们可以选择投射日期,这很少是必要的.

错误的方法:

cast(convert(char(11), getdate(), 113) as datetime)
Run Code Online (Sandbox Code Playgroud)

错误的方法是转换为字符串,截断字符串,然后转换回日期时间.这是错误的,原因有二:1)它可能无法在所有语言环境中运行; 2)它是关于最慢的可行方式......而不仅仅是一点点; 它比其他选项慢一个数量级或两个数量级.


更新这最近得到了一些投票,所以我想补充说,自从我发布这个以来,我已经看到一些非常可靠的证据表明Sql Server将优化"正确"方式和"快速"方式之间的性能差异,这意味着你现在应该支持前者.

在任何一种情况下,您都希望编写查询以避免首先执行此操作.你应该在数据库上做这项工作是非常罕见的.

在大多数地方,数据库已经成为你的瓶颈.通常,服务器是增加硬件以提高性能的最昂贵的服务器,也是最难获得正确添加硬件的服务器(例如,您必须平衡磁盘与内存).从技术角度和商业角度来看,它也是最难扩展的; 在技​​术上添加Web或应用程序服务器比数据库服务器更容易,即使这是假的,您也不需要为IIS或Apache支付每服务器许可证20,000美元.

我想说的是,只要有可能,你应该在应用程序级别完成这项工作.你应该发现自己在Sql Server上截断日期时间的唯一一次是当你需要按日分组时,即使这样你也应该有一个额外的列设置为计算列,保持在插入/更新时间,或维护在应用程序逻辑.从数据库中获取这个破坏索引,重大cpu的工作.

  • 这种"正确"的方式只是偶然起作用.它的编写方式就好像DateAdd的语法是(interval,date,increment),但事实并非如此.它是(间隔,增量,日期).当我试图将日期截断到本月的第一天时,我偶然发现了这一点:SELECT DATEADD(m,0,DATEDIFF(m,0,GETDATE()))不起作用,但SELECT DATEADD(m,DATEDIFF(m, 0,GETDATE()),0).至少,这是我在2008R2中看到的. (9认同)
  • 根据我刚刚运行的基准测试,"快速方式"仍然是sql 2008的最快方式 (6认同)
  • 仅供参考:http://stackoverflow.com/q/1177449/27535和http://stackoverflow.com/q/133081/27535 dateadd/datediff"赢...".对于单个变量,谁当然在乎,并且希望你有计算列或超过一百万行:-) (3认同)
  • 他们_all_在日期时间列上工作.`getdate()`这里是您可能拥有的日期时间源的替身. (2认同)
  • 回复:“将这些占用大量 CPU 的工作从数据库中移走。”这真的有那么多工作吗?我的意思是我的*电话*可以每秒 60 次渲染一个非常复杂的 3D 环境,其中包含数百万个纹理映射三角形。从 SQL Server 中的日期中删除时间真的会导致您甚至可以测量的问题(即使是数百万行)吗? (2认同)

DJ.*_*DJ. 44

仅适用于SQL Server 2008

CAST(@SomeDateTime AS Date) 
Run Code Online (Sandbox Code Playgroud)

然后如果你愿意,把它重新投入日期时间

CAST(CAST(@SomeDateTime AS Date) As datetime)
Run Code Online (Sandbox Code Playgroud)


Luc*_*ero 21

只是为了更完整的答案,这里是一个截断到任何日期部分的工作方式,包括分钟(用GETDATE()截断日期替换).

这与接受的答案不同,您不仅可以使用dd(天),还可以使用任何日期部分(请参阅此处):

dateadd(minute, datediff(minute, 0, GETDATE()), 0)
Run Code Online (Sandbox Code Playgroud)

请注意,在上面的表达式中,它0是一年开始时的常量日期(1900-01-01).如果需要截断为较小的部分,例如秒或毫秒,则需要采用更接近截断日期的常量日期以避免溢出.


Tom*_*ter 7

我必须这样做时在网上找到的片段是:

 dateadd(dd,0, datediff(dd,0, YOURDATE))
 e.g.
 dateadd(dd,0, datediff(dd,0, getDate()))
Run Code Online (Sandbox Code Playgroud)

  • 整齐!我会使用拆分日期部分并使用字符串处理将它们重新组合在一起.可能不相关,但SQL2008具有纯日期数据类型而没有时间元素. (2认同)