在SQL Server 2008中截断日期时间值(如删除小时、分钟和秒)的最佳方法是什么?
例如:
declare @SomeDate datetime = '2009-05-28 16:30:22' select trunc_date(@SomeDate) ----------------------- 2009-05-28 00:00:00.000
当我不得不这样做时,我在网上找到的片段是:
dateadd(dd,0, datediff(dd,0, YOURDATE)) e.g. dateadd(dd,0, datediff(dd,0, getDate()))
这继续频繁地收集额外的投票,甚至几年后,所以我需要更新它的现代版本的Sql Server。对于Sql Server 2008及以后的版本,它很简单:
cast(getDate() As Date)
请注意,接近底部的最后三段仍然适用,您通常需要后退一步,找到一种在一开始就避免强制转换的方法。
但也有其他方法可以做到这一点。以下是最常见的。
正确的方式(自Sql Server 2008以来新增):
cast(getdate() As Date)
正确的方式(旧):
dateadd(dd, datediff(dd,0, getDate()), 0)
它现在已经很老了,但仍然值得了解,因为它也可以很容易地适应其他时间点,比如每月、分钟、小时或年的第一个时刻。
这种正确的方法使用ansi标准中有文档的函数,这些函数保证可以工作,但可能会稍慢一些。它的工作原理是找出从第0天到今天有多少天,然后把这些天加到第0天。无论您的datetime是如何存储的,无论您的语言环境是什么,它都将工作。
最快捷的方法:
cast(floor(cast(getdate() as float)) as datetime)
这是因为datetime列存储为8字节二进制值。将它们强制转换为浮动,将它们向下转换以删除分数,当您将值强制转换回datetime时,值的时间部分将消失。它只是位移位,没有复杂的逻辑,并且它是非常快。
请注意,这依赖于微软可以随时更改的实现细节,即使是在自动服务更新中。它也不是很便携。在实践中,这种实现不太可能很快改变,但如果您选择使用它,那么意识到其中的危险仍然很重要。既然我们可以选择约会,那就没什么必要了。
错误的方式:
cast(convert(char(11), getdate(), 113) as datetime)
错误的工作方式是转换为字符串,截断字符串,然后转换回日期时间。它是错误的,有两个原因:1)它可能不能在所有地区工作,2)这是最慢的可能的方式来做到这一点…而且不是一点点;它比其他选项慢了一两个数量级。
更新这已经得到了一些投票最近,所以我想补充它,因为我张贴了这个,我已经看到了一些相当确凿的证据,Sql Server将优化“正确”的方式和“快速”的方式之间的性能差异,这意味着你现在应该支持前者。
在任何一种情况下,你都想在编写查询时,首先要避免这样做的需要。在数据库上执行此工作的情况非常少。
在大多数情况下,数据库已经成为您的瓶颈。通常情况下,为提高性能而添加硬件的服务器是最昂贵的,也是最难正确添加这些硬件的服务器(例如,您必须平衡磁盘和内存)。从技术和商业角度来看,这也是最难向外扩展的;从技术上讲,添加一个web或应用服务器比添加一个数据库服务器要容易得多,即使这是错误的,你也不需要为IIS或apache的每个服务器许可证支付2万美元以上。
我试图说明的观点是,只要有可能,您就应该在应用程序级别上完成这项工作。你应该发现自己在Sql Server上截断datetime的只有时间是你需要按天分组的时候,即使这样,你也应该有一个额外的列设置为计算列,在插入/更新时维护,或者在应用程序逻辑中维护。从数据库中删除这种破坏索引、cpu负荷大的工作。
仅适用于SQL Server 2008
CAST(@SomeDateTime AS Date)
然后将其转换回datetime
CAST(CAST(@SomeDateTime AS Date) As datetime)
在SQl 2005中,你的trunc_date函数可以这样写。
(1)
CREATE FUNCTION trunc_date(@date DATETIME) RETURNS DATETIME AS BEGIN CAST(FLOOR( CAST( @date AS FLOAT ) )AS DATETIME) END
第一种方法要干净得多。它只使用3个方法调用,包括最后的CAST(),并且不执行字符串连接,这是一个自动加。此外,这里没有大型类型强制转换。如果您可以想象可以表示日期/时间戳,那么从日期转换到数字再转换回日期是一个相当简单的过程。
(2)
CREATE FUNCTION trunc_date(@date DATETIME) RETURNS DATETIME AS BEGIN SELECT CONVERT(varchar, @date,112) END
如果你担心微软的datetimes(2)或(3)的实现可能是好的。
(3)
CREATE FUNCTION trunc_date(@date DATETIME) RETURNS DATETIME AS BEGIN SELECT CAST((STR( YEAR( @date ) ) + '/' +STR( MONTH( @date ) ) + '/' +STR( DAY(@date ) ) ) AS DATETIME END
第三,更详细的方法。这需要将日期分解为年、月和日部分,以“yyyy/mm/dd”格式将它们组合在一起,然后将其转换为日期。该方法涉及7个方法调用,包括最后的CAST(),更不用说字符串连接了。
CONVERT(DATE, <yourdatetime>) or CONVERT(DATE, GetDate()) or CONVERT(DATE, CURRENT_TIMESTAMP)
对于那些来到这里寻找一种方法来截断一个DATETIME字段小于一天,例如每分钟,你可以使用这个:
SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) + (FLOOR((CAST(GETDATE() AS FLOAT) - FLOOR(CAST(GETDATE() AS FLOAT))) * 1440.0) + (3.0/86400000.0)) / 1440.0 AS DATETIME)
所以如果今天是2010-11-26 14:54:43.123,那么返回2010-11-26 14:54:00.000。
2010-11-26 14:54:43.123
2010-11-26 14:54:00.000
要更改它的运行时间间隔,请将1440.0替换为一天中的间隔数,例如:
24hrs = 24.0 (for every hour) 24hrs / 0.5hrs = 48.0 (for every half hour) 24hrs / (1/60) = 1440.0 (for every minute)
(总是在末尾放置.0以隐式转换为浮点数。)
.0
对于那些想知道在我的计算中(3.0/86400000)是用来做什么的人来说,SQL Server 2005似乎没有准确地从FLOAT转换到DATETIME,所以这增加了3毫秒。
(3.0/86400000)
FLOAT
DATETIME
为了得到更完整的答案,这里有一个截断到任何日期部分的工作方法,包括分钟(将GETDATE()替换为要截断的日期)。
GETDATE()
这与公认的答案不同,因为你不仅可以使用dd(天),还可以使用任何日期部分(参见在这里):
dd
dateadd(minute, datediff(minute, 0, GETDATE()), 0)
注意,在上面的表达式中,0是一年开始的一个常量日期(1900-01-01)。如果需要截断为更小的部分,例如秒或毫秒,则需要取一个更接近要截断的日期的常数日期,以避免溢出。
0
TRUNC(aDate, 'DD')将截断分钟,秒和小时
SRC: http://www.techonthenet.com/oracle/functions/trunc_date.php
select cast(getdate() as float)) as datetime) 引用:http://microsoftmiles.blogspot.com/2006/11/remove-time-from-datetime-in-sql-server.html
这个查询应该会给你一个等同于Oracle中的trunc(sysdate)的结果。
trunc(sysdate)
SELECT * FROM your_table WHERE CONVERT(varchar(12), your_column_name, 101) = CONVERT(varchar(12), GETDATE(), 101)
希望这能有所帮助!
你也可以从datetime变量中提取date using Substring,强制转换回datetime将忽略time部分。
using Substring
declare @SomeDate datetime = '2009-05-28 16:30:22' SELECT cast(substring(convert(varchar(12),@SomeDate,111),0,12) as Datetime)
同样,你也可以访问datetime变量的一部分,并将它们合并为一个截断日期的构造,就像这样:
SELECT cast(DATENAME(year, @Somedate) + '-' + Convert(varchar(2),DATEPART(month, @Somedate)) + '-' + DATENAME(day, @Somedate) as datetime)
Oracle:
TRUNC(SYSDATE, 'MONTH')
SQL服务器:
DATEADD(DAY, - DATEPART(DAY, DateField) + 1, DateField)
可以类似地用于从日期截断分钟或小时。
你可以这样做(SQL 2008):
@SomeDate date = getdate()
select @SomeDate
2009-05-28
在使用分析时,您可能需要大量的日期\时间截断。所以我做了一个小函数来帮助整理:
CREATE FUNCTION TRUNC_DATE ( @datetime datetime, -- datetime to be truncated @level VARCHAR(10) -- truncation level: year, month, day, hour and minute ) RETURNS DATETIME AS BEGIN IF (UPPER(@level) = 'YEAR') RETURN DATEADD(YEAR, DATEDIFF(YEAR, 0, @datetime), 0) ELSE IF (UPPER(@level) = 'MONTH') RETURN DATEADD(MONTH, DATEDIFF(MONTH, 0, @datetime), 0) ELSE IF(UPPER(@level) = 'DAY') RETURN DATEADD(DAY, DATEDIFF(DAY, 0, @datetime), 0) ELSE IF (UPPER(@level) = 'HOUR') RETURN DATEADD(HOUR, DATEDIFF(HOUR, 0, @datetime), 0) ELSE IF (UPPER(@level) = 'MINUTE') RETURN DATEADD(MINUTE, DATEDIFF(MINUTE, 0, @datetime), 0) RETURN @datetime END GO
计算函数(用you列更改GETDATE()):
SELECT DBO.TRUNC_DATE(GETDATE(), 'YEAR') YEAR; SELECT DBO.TRUNC_DATE(GETDATE(), 'MONTH') YEAR_MONTH; SELECT DBO.TRUNC_DATE(GETDATE(), 'DAY') YEAR_MONTH_DAY; SELECT DBO.TRUNC_DATE(GETDATE(), 'HOUR') YEAR_MONTH_DAY_HOUR; SELECT DBO.TRUNC_DATE(GETDATE(), 'MINUTE') YEAR_MONTH_DAY_HOUR_MINUTE;
输出: