Нужно вычислить сумму секунд, используя функцию из строковой переменной, используя SQL - PullRequest
6 голосов
/ 13 мая 2019

В таблице с именем Adventurous есть столбец с именем продолжительности. Столбец имеет значения, указанные ниже. В столбце суффикс «H» - часы, суффикс «M» - минуты, а суффикс «S» - секунды.Как мы можем выбрать часы, минуты и секунды и преобразовать все в секунды, то есть сумму всех часов, минут и секунд в виде секунд.

Duration 
--------
PT10M13S
PT13M22S
PT1H2M18S
PT11S

Я попытался использовать подстроку и charindex, как показано ниже, и попыталсясоздать функцию, но получаю ошибку:

Declare @Duration varchar(30) ='PT16H13M42S', @Dur varchar(10)
Declare @hours int
declare @mins int
declare @secs int
declare @len int

select @len = len(substring (@Duration, 3, len(@Duration))), @Dur=substring (@Duration, 3, len(@Duration))
select @hours = charindex('H', @Dur)

select substring(@Dur, 1, @hours-1)

select @Duration=substring (@Dur, @hours+1, len(@Dur))
select @mins = charindex('M', @Duration)

select substring(@Duration, 1, @mins-1)

select @Dur=substring (@Duration, @mins+1, len(@Duration))
select @secs= charindex('S', @Dur)

select substring(@Dur, 1, @Secs-1)

select @len, @Dur, @Duration

пример PT1H2M18S = 1 * 3600 + 2 * 60 + 18 = 3738

Ответы [ 4 ]

2 голосов
/ 13 мая 2019

Другой возможный подход - преобразовать ввод текста Duration в правильное выражение T-SQL ('PT1H2M18S' будет преобразовано в '1*3600+2*60+18*1+0').После этого рассмотрим следующие два варианта:

  • Создать и выполнить динамический оператор, который будет оценивать каждое выражение, или

  • Определить функцию для выполнениявычисления

Ввод:

CREATE TABLE #Data (
    Duration varchar(50)
)
INSERT INTO #Data
    (Duration)
VALUES
    ('PT10M13S'),
    ('PT13M22S'),
    ('PT1H2M18S'),
    ('PT100H'),
    ('PT11S')

Динамический оператор:

DECLARE @stm nvarchar(max)
SET @stm = N''

SELECT @stm = @stm + 
    CONCAT(
        'UNION ALL SELECT ''',
        Duration,
        ''' AS [Duration], ', 
        REPLACE(REPLACE(REPLACE(REPLACE(Duration, 'H', '*3600+'), 'M', '*60+'), 'S', '*1+'), 'PT', ''), 
        '0 AS [Seconds] '
    )
FROM #Data
SET @stm = STUFF(@stm, 1, 10, N'')

EXEC (@stm)

Пользовательская функция:

CREATE FUNCTION [udfCalculateHMS] (@expression varchar(100))
RETURNS int
AS
BEGIN
   DECLARE @result int
   DECLARE @s varchar(100)

   --
   SET @result = 0
   WHILE (CHARINDEX('+', @expression) > 0) BEGIN
      SET @s = SUBSTRING(@expression, 1, CHARINDEX('+', @expression) - 1)
      SET @expression = STUFF(@expression, 1, CHARINDEX('+', @expression), '')
      SET @result = @result + 
          CONVERT(int, SUBSTRING(@s, 1, CHARINDEX('*', @s) - 1)) * 
          CONVERT(int, STUFF(@s, 1, CHARINDEX('*', @s), ''))
   END

   -- Return value
   RETURN @result
END

SELECT 
    Duration, 
    dbo.udfCalculateHMS(CONCAT(REPLACE(REPLACE(REPLACE(REPLACE(Duration, 'H', '*3600+'), 'M', '*60+'), 'S', '*1+'), 'PT', ''), '0')) AS Seconds
FROM #Data

Вывод:

Duration    Seconds
PT10M13S    613
PT13M22S    802
PT1H2M18S   3738
PT100H      360000
PT11S       11
2 голосов
/ 13 мая 2019

Попробуйте это:

Declare @t table (duration varchar(50))

insert into @t values  ('PT1H2M18S')

select   
        convert(int,substring(duration,CHARINDEX('PT',duration)+2,(CHARINDEX('H',duration)-CHARINDEX('PT',duration))-2))*3600 +
        convert(int,substring(duration,CHARINDEX('H',duration)+1,(CHARINDEX('M',duration)-CHARINDEX('H',duration))-1))*60 +
        convert(int,substring(duration,CHARINDEX('M',duration)+1,(CHARINDEX('S',duration)-CHARINDEX('M',duration))-1))
        from @t
0 голосов
/ 13 мая 2019

Добавление ответа с использованием Таблица подсчета и в основном надежный ISNUMERIC Функция SQL

Это должно быть хорошо для небольших наборов данных.Я также предполагаю, что у вас есть действительные числа, т.е. часовая часть не> 24, минутная часть или секундная часть не> 60

create table #t(duration nvarchar(max));
insert into #t values
('PT10M13S')
,('PT13M22S')
,('PT1H2M18S')
,('PT11S')

select 
    totalseconds= sum(m.factor* case when ISNUMERIC(substring(duration, r-2,2))=1 then substring(duration, r-2,2) else substring(duration, r-1,1) end ), 
    duration from #t
cross join 
      (
       select r=row_number() over (order by (select NULL))-1
       from sys.objects s1 cross join sys.objects s2
)t
join 
(values('S',1),('M',60),('H',3600)) m(part,factor)
on r<=len(duration) and substring(duration, r,1) =m.part
group by duration

drop table #t

PS: см. Эту ссылку SO, которая предполагает, что скалярный UDF быстрее, чем ISNUMERIC Самый быстрый способ проверить, является ли символ цифрой?

0 голосов
/ 13 мая 2019

Так я бы переместился по строке, чтобы получить правильные целочисленные значения. Количество символов для смещения может меняться в зависимости от того, можете ли вы иметь различное количество символов в час, минуту и ​​секунду. Но принцип должен помочь вам.

Declare @Duration varchar(30) ='PT16H13M42S'


select * from 
(values(substring(@Duration,CHARINDEX('PT',@duration)+2,(CHARINDEX('H',@Duration)-CHARINDEX('PT',@Duration))-2),
        substring(@Duration,CHARINDEX('H',@duration)+1,(CHARINDEX('M',@Duration)-CHARINDEX('H',@Duration))-1),
        substring(@Duration,CHARINDEX('M',@duration)+1,(CHARINDEX('S',@Duration)-CHARINDEX('M',@Duration))-1))) duration ([Hours], [Minutes], [Seconds]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...