SQL Parse持续时间字符串到秒

时间:2016-08-04 02:36:35

标签: sql-server

我使用的是SQL Server 12.0.4213.0,并且是高级SQL查询的新手。

我有一个名为持续时间nvarchar列,其中包含以下两种格式之一的时间跨度:39 Seconds如果持续时间低于1分钟,则格式为{{1 }}。请注意,每天/每小时/分钟/秒可以是单数或复数。同样在第一种格式中,如果日期为0,则将省略日期(与小时相同)。

我需要将持续时间转换为表示总秒数的整数。 1 Day 18 Hours 2 Minutes应返回90,1 Minute 30 Seconds应返回39.

我认为这可以通过嵌套的CASE语句来完成。数据集非常大,所以我想确保我有效地接近这个。任何帮助将不胜感激。

我在PowerShell中使用的一种方法是在空格字符上拆分持续时间列,将结果数组递增计数器循环2,取39 Seconds并将其乘以相应的由array[counter]确定的秒值,将产品添加到总秒数。

2 个答案:

答案 0 :(得分:1)

这有点复杂,但并不可怕。解决这个问题的方法是从字符串中删除Day(s),Hours(s),Minutes(s),Second(s)标签,并用一些分隔字符串/字符替换它们。

然后,您可以使用CTE分割结果值。

然后,您将根据每个部分在分隔字符串中的位置,以秒为单位创建时间跨度。

最后,对结果时间跨度 - 秒 - 秒进行求和。

编辑:现在定义为功能

像这样:

CREATE FUNCTION fn_getDurationSeconds(@duration varchar(100)) returns int 
as
BEGIN 
    DECLARE @durationSeconds INT = 0;

    with split (duration, part, remainder) as
    (
        SELECT 
            duration,
            left(duration, CHARINDEX(':', duration)-1),
            right(duration, LEN(duration) - CHARINDEX(':', duration))
        FROM
        (
            SELECT 
                REPLACE(
                    REPLACE(
                        REPLACE(
                            REPLACE(
                                REPLACE(
                                    REPLACE(
                                        CASE WHEN @duration LIKE '% Day'   or @duration like '% Days'    THEN @Duration + ' 0 Hours 0 Minutes 0 Seconds'
                                             WHEN @duration LIKE '% Hour'  or @duration like '% Hours'   THEN @Duration + ' 0 Minutes 0 Seconds'
                                             WHEN @duration LIKE '% Minute'or @duration like '% Minutes' THEN @Duration + ' 0 Seconds' 
                                             ELSE @Duration
                                        END, ' Day', ':'),
                                    ' Hour', ':'),
                                ' Minute', ':'),
                            ' Second', ':00'),
                        's', ''),
                    ' ', '') duration

        ) t
        union all
        select
            duration, 
            left(remainder, CHARINDEX(':', remainder) - 1),
            right(remainder,  LEN(remainder) - CHARINDEX(':', remainder))
        from split
        where CHARINDEX(':', remainder) > 0 
    )
    SELECT @durationSeconds = sum(seconds)
    FROM 
    (
        select 
            duration,
            CASE row_number() over(partition by duration order by LEN(remainder) ) 
                WHEN 4 THEN 24 * 60 * 60
                WHEN 3 THEN 60 * 60
                WHEN 2 THEN 60
                WHEN 1 THEN 1
            END * CAST(part AS INT) Seconds
        from split 
    ) t
    group by duration
    order by duration


    RETURN @durationSeconds
END

答案 1 :(得分:0)

另一个选择是使用substringpatindex以及几个常用表表达式来获得所需的结果:

首先,创建并填充样本表:( 在将来的问题中将此步骤保存起来)

DECLARE @T AS TABLE
(
    Duration varchar(40),
    NumberOfSeconds int
)

INSERT INTO @T (Duration) VALUES
('39 Seconds'),
('2 Minutes 4 Seconds'),
('1 Hours 7 Minutes 17 Seconds'),
('3 Days 9 Hour 8 Minutes 25 Seconds')

然后,使用一个cte来保存每个单词的patindex个结果 这个cte只是为了节省我们一遍又一遍地编写patindex的需要。 添加另一个cte到这个,将使用substring使用第一个cte提取每个时间部分的值:

;WITH cte1 as
(
    SELECT  *,
            PATINDEX('%Day%', Duration) As DaysIndex,
            PATINDEX('%Hour%', Duration) As HoursIndex,
            PATINDEX('%Minute%', Duration) As MinutesIndex,
            PATINDEX('%Second%', Duration) As SecondIndex
    FROM @T
), cte2 as
(
SELECT  *,

        CASE WHEN DaysIndex > 0 THEN
            CAST(SUBSTRING(Duration, 0, DaysIndex) As int) * 60 * 60 * 24
        ELSE
            0
        END As D,
        CASE WHEN HoursIndex > 0 THEN
            CAST(
            SUBSTRING(Duration, 
                CASE WHEN DaysIndex > 0 THEN DaysIndex + 4 
                ELSE 0 
                END, 

                CASE WHEN DaysIndex > 0 THEN HoursIndex - DaysIndex - 4 
                ELSE HoursIndex 
                END
            ) As int) * 60 * 60
        ELSE
            0
        END As H,
        CASE WHEN MinutesIndex > 0 THEN
            CAST(
            SUBSTRING(Duration, 
                CASE WHEN HoursIndex > 0 THEN HoursIndex + 5 
                ELSE 0 
                END, 

                CASE WHEN HoursIndex > 0 THEN MinutesIndex - HoursIndex - 5 
                ELSE MinutesIndex 
                END
            ) As int) * 60
        ELSE
            0
        END As M,
        CASE WHEN SecondIndex > 0 THEN
            CAST(
            SUBSTRING(Duration, 
                CASE WHEN MinutesIndex > 0 THEN MinutesIndex + 7 
                ELSE 0 
                END, 

                CASE WHEN MinutesIndex > 0 THEN SecondIndex - MinutesIndex - 7 
                ELSE SecondIndex 
                END
            ) As int) 
        ELSE
            0
        END As S
FROM cte1
)

现在,更新NumberOfSeconds列:

UPDATE cte2 
SET NumberOfSeconds = D + H + M + S

验证更新结果:

SELECT *
FROM @T 

结果:

Duration                                 NumberOfSeconds
---------------------------------------- ---------------
39 Seconds                               39
2 Minutes 4 Seconds                      124
1 Hours 7 Minutes 17 Seconds             4037
3 Days 9 Hour 8 Minutes 25 Seconds       292105