有没有更好的方法将SQL日期时间从hh:mm:ss转换为hhmmss?

时间:2009-05-27 17:37:49

标签: sql sql-server tsql

我必须编写一个SQL视图,它将日期时间列的时间部分作为字符串以hhmmss格式返回(显然SAP BW不理解hh:mm:ss)。

此代码是SAP推荐的方法,但我认为必须有更好,更优雅的方法来实现这一目标

TIME = case len(convert(varchar(2), datepart(hh, timecolumn)))
             when 1 then       /* Hour Part of TIMES */
               case convert(varchar(2), datepart(hh, timecolumn))
                 when '0' then '24'    /* Map 00 to 24 ( TIMES ) */
                 else '0' + convert(varchar(1), datepart(hh, timecolumn))
               end
            else convert(varchar(2), datepart(hh, timecolumn))
            end
         + case len(convert(varchar(2), datepart(mi, timecolumn)))
              when 1 then '0' + convert(varchar(1), datepart(mi, timecolumn))
              else convert(varchar(2), datepart(mi, timecolumn))
           end
         + case len(convert(varchar(2), datepart(ss, timecolumn)))
              when 1 then '0' + convert(varchar(1), datepart(ss, timecolumn))
              else convert(varchar(2), datepart(ss, timecolumn))
           end

这实现了预期的结果,21:10:45显示为211045。

我喜欢更紧凑,更易读的东西,但到目前为止我还没有想出任何有用的东西。

7 个答案:

答案 0 :(得分:5)

注意:

问题是该列的数据类型为DATETIME,而不是较新的(SQL Server 2008)TIME数据类型。

<强>解答:

  REPLACE(CONVERT(VARCHAR(8),timecolumn,8),':','')

让我们打开它。

首先,CONVERT将日期时间的时间部分格式化为varchar,格式为'hh:mi:ss'(24小时制),格式样式值为8。

接下来,REPLACE函数删除冒号,以'hhmiss'格式获取varchar。

这应该足以以您需要的格式获取可用的字符串。


后续问题

(OP问题提问)

内联表达式是否比用户定义的函数更快/更少服务器密集?

快速回答是肯定的。更长的答案是:它取决于几个因素,你真的需要衡量性能,以确定这是否真实。

我创建并执行了一个基本的测试用例:

    -- sample table
    create table tmp.dummy_datetimes (c1 datetime)

    -- populate with a row for every minute between two dates
    insert into tmp.dummy_datetimes
    select * from udfDateTimes('2007-01-01','2009-01-01',1,'minute')

    (1052641 row(s) affected)

    -- verify table contents
    select min(c1) as _max
         , max(c1) as _min
         , count(1) as _cnt
      from tmp.dummy_datetimes

    _cnt    _min                    _max
    ------- ----------------------- -----------------------
    1052641 2007-01-01 00:00:00.000 2009-01-01 00:00:00.000

(注意,udfDateTimes函数以指定的间隔返回两个日期时间值之间的所有日期时间值的集合。在这种情况下,我用虚拟表填充每一分钟的行,整整两年。这是一个顺序百万(2x365x24x60)行。

现在,用户定义的函数使用相同的语法执行与内联表达式相同的转换:

    CREATE FUNCTION [tmp].[udfStrippedTime] (@ad DATETIME)
    RETURNS VARCHAR(6)
    BEGIN
    -- Purpose: format time portion of datetime argument to 'hhmiss'
    -- (for performance comparison to equivalent inline expression)
    -- Modified:
    -- 28-MAY-2009 spencer7593

       RETURN replace(convert(varchar(8),@ad,8),':','')

    END

注意:我知道该功能未定义为DETERMINISTIC。 (我认为这需要使用模式绑定和其他声明来声明函数,例如PRAGMA所需的Oracle。)但是由于每个日期时间值在表中都是唯一的,这应该无关紧要。该函数必须为每个不同的值执行,即使它已被正确声明为DETERMINISTIC

我不是这里的SQL Server'用户定义函数'大师,所以我可能会遗漏一些其他无意中会不必要地降低函数速度的内容。

好。

因此,对于测试,我交替运行了每个查询,先是一个,然后是另一个,一遍又一遍地。第一次运行的经过时间与随后的运行一致。 (通常情况并非如此,我们希望省去第一次运行的时间。)SQL Server Management Studio将查询已用时间报告到最接近的秒,格式为hh:mi:ss,这就是我在此报告的内容。

    -- elapsed times for inline expression
    select replace(convert(varchar(8),c1,8),':','') from tmp.dummy_datetimes

    00:00:10
    00:00:11
    00:00:10

    -- elapsed times for equivalent user defined function
    select tmp.udfStrippedTime(c1) from tmp.dummy_datetimes

    00:00:15
    00:00:15
    00:00:15

对于这个测试用例,我们观察到用户定义的函数比等效的内联表达式慢了45%。

HTH

答案 1 :(得分:2)

您可以使用用户定义的函数,如:

create FUNCTION [dbo].[udfStrippedTime]
(
    @dt datetime
)
RETURNS varchar(32)
AS
BEGIN
    declare @t varchar(32)
    set @t = convert( varchar(32), @dt, 108 )
    set @t = left(@t,2) + substring(@t,4,2)

    RETURN @t
END

然后

select dbo.udfStrippedTime(GETDATE())

秒的逻辑留给读者练习

答案 2 :(得分:2)

修改2:更新为处理0 - &gt; 24转换,以及更短的版本:

select replace(left(replace(convert(char,getdate(),8),':',''),2),'00','24') + right(replace(convert(char,getdate(),8),':',''),4)

回到稍长的版本:)

答案 3 :(得分:2)

这是一个问题。格式化是否需要在Db服务器上进行?服务器本身真的只关心,并且针对存储数据进行了优化。查看数据通常是Db上面的hte层的责任(在严格的学术意义上,现实世界有点混乱)

例如,如果要将结果输出到绑定到GridControl的ASP.NET页面,则只需在绑定到列时指定DataFormattingString即可。如果您使用c#将其写入文本文件,则在拉取数据时,您只需将格式字符串传递给.ToString()函数。

如果你需要它专门在DbServer上,那么几乎每个解决方案都会变得混乱,因为你需要的时间格式,虽然紧凑和逻辑,不是服务器将识别的时间格式,所以你需要将其作为字符串操纵。

答案 4 :(得分:2)

这处理00 - &gt; 24转换

SELECT CASE WHEN DATEPART(hh,timecolumn) = 0 
    THEN  '24' + SUBSTRING(REPLACE(CONVERT(varchar(8),timecolumn, 108),':',''),3,4)
    ELSE REPLACE(CONVERT(varchar(8),timecolumn, 108),':','') END

答案 5 :(得分:1)

SELECT replace(convert(varchar(15),datetimefield,108),':','') 来自表

答案 6 :(得分:0)

SELECT REPLACE('2009-05-27 12:49:19',':','') 2009-05-27 124919