我使用的是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]
确定的秒值,将产品添加到总秒数。
答案 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)
另一个选择是使用substring
和patindex
以及几个常用表表达式来获得所需的结果:
首先,创建并填充样本表:( 请在将来的问题中将此步骤保存起来)
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