在 SQL Server 2008 中截断日期时间值(如删除小时、分钟和秒)的最佳方法是什么?
例如:
declare @SomeDate datetime = '2009-05-28 16:30:22'
select trunc_date(@SomeDate)
-----------------------
2009-05-28 00:00:00.000
在 SQL Server 2008 中截断日期时间值(如删除小时、分钟和秒)的最佳方法是什么?
例如:
declare @SomeDate datetime = '2009-05-28 16:30:22'
select trunc_date(@SomeDate)
-----------------------
2009-05-28 00:00:00.000
这继续频繁地收集额外的选票,甚至几年后,所以我需要为现代版本的 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 天。无论您的日期时间如何存储,也无论您的语言环境是什么,它都会起作用。
快速方法:
cast(floor(cast(getdate() as float)) as datetime)
这是因为 datetime 列存储为 8 字节二进制值。将它们转换为浮点数,将它们降低以删除分数,当您将它们转换回日期时间时,值的时间部分就消失了。这一切都只是位移,没有复杂的逻辑,而且速度非常快。
请注意,这依赖于 Microsoft 可以随时更改的实施细节,即使是在自动服务更新中也是如此。它也不是很便携。在实践中,这种实现不太可能很快改变,但如果你选择使用它,意识到危险仍然很重要。现在我们可以选择将其投射为日期,这几乎没有必要。
错误的方法:
cast(convert(char(11), getdate(), 113) as datetime)
错误的方法是转换为字符串、截断字符串并转换回日期时间。这是错误的,有两个原因:1)它可能不适用于所有语言环境和 2)它是最慢的方法......而且不仅仅是一点点;它比其他选项慢一个或两个数量级。
更新这最近得到了一些投票,所以我想补充一点,自从我发布这个我已经看到一些非常可靠的证据表明 Sql Server 将优化“正确”方式和“快速”方式之间的性能差异,这意味着您现在应该支持前者。
在任何一种情况下,您都希望编写查询以避免一开始就需要这样做。您很少会在数据库上进行这项工作。
在大多数地方,数据库已经是你的瓶颈。通常,为提高性能而添加硬件最昂贵的服务器,以及最难正确添加硬件的服务器(例如,您必须平衡磁盘和内存)。从技术和商业角度来看,它也是最难向外扩展的;从技术上讲,添加 Web 或应用程序服务器比添加数据库服务器要容易得多,即使这是错误的,您也不必为 IIS 或 apache 的每个服务器许可证支付 20,000 美元以上。
我要说明的一点是,只要有可能,您应该在应用程序级别完成这项工作。您发现自己在 Sql Server 上截断日期时间的唯一一次是当您需要按天分组时,即便如此,您可能应该将额外的列设置为计算列,在插入/更新时维护,或维护在应用程序逻辑中。从您的数据库中获取这种破坏索引、占用大量 CPU 资源的工作。
仅适用于 SQL Server 2008
CAST(@SomeDateTime AS Date)
如果需要,然后将其转换回日期时间
CAST(CAST(@SomeDateTime AS Date) As datetime)
只是为了获得更完整的答案,这是一种将任何日期部分向下截断并包括分钟的工作方式(替换GETDATE()
为要截断的日期)。
这与公认的答案不同,因为您不仅可以使用dd
(天),还可以使用任何日期部分(请参见此处):
dateadd(minute, datediff(minute, 0, GETDATE()), 0)
请注意,在上面的表达式中,0
是年初的固定日期 (1900-01-01)。如果您需要截断到更小的部分,例如秒或毫秒,则需要采用更接近要截断的日期的常量日期以避免溢出。
当我不得不这样做时,我在网上找到的片段是:
dateadd(dd,0, datediff(dd,0, YOURDATE))
e.g.
dateadd(dd,0, datediff(dd,0, getDate()))
CONVERT(DATE, <yourdatetime>) or CONVERT(DATE, GetDate()) or CONVERT(DATE, CURRENT_TIMESTAMP)
在 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
如果您担心微软对日期时间 (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(),更不用说字符串连接了。
对于那些来这里寻找一种方法来将 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
。
要更改它的间隔,请将 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)
(始终将 a.0
放在末尾以隐式转换为浮点数。)
对于那些想知道(3.0/86400000)
在我的计算中是什么的人,SQL Server 2005 似乎并没有准确地从FLOAT
转换到DATETIME
准确,所以这在铺平之前增加了 3 毫秒。
选择 cast(floor(cast(getdate() as float)) as datetime) 参考:http ://microsoftmiles.blogspot.com/2006/11/remove-time-from-datetime-in-sql-server.html
此查询应为您提供trunc(sysdate)
与 Oracle 中相同的结果。
SELECT *
FROM your_table
WHERE CONVERT(varchar(12), your_column_name, 101)
= CONVERT(varchar(12), GETDATE(), 101)
希望这可以帮助!
您还可以using Substring
从 datetime 变量中提取日期,然后转换回 datetime 将忽略时间部分。
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)
甲骨文:
TRUNC(SYSDATE, 'MONTH')
SQL 服务器:
DATEADD(DAY, - DATEPART(DAY, DateField) + 1, DateField)
可以类似地用于从日期截断分钟或小时。
你可以这样做(SQL 2008):
声明 @SomeDate 日期 = 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
评估函数(用你改变 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;
输出:
TRUNC(aDate, 'DD') 将截断分钟、秒和小时
SRC:http ://www.techonthenet.com/oracle/functions/trunc_date.php