【问题标题】:convert time in string to number of hours将字符串中的时间转换为小时数
【发布时间】:2020-12-04 22:16:53
【问题描述】:

我正在尝试将字符串中的时间转换为小时数。

例如

| Hours in text       | Number of hours |
| ------------------- | --------------- |
| 1 minute            | 0.02            |
| 30 minutes          | 0.5             |
| 2 Hours 15 Minutes  | 2.25            |
| 8 Hours             | 8               |
| 4 Hours 30 Minutes  | 4.5             |
| 1 Hour              | 1               |

DECLARE @tabvar TABLE(TimeInText VARCHAR(100));

INSERT INTO @tabvar(TimeInText)
SELECT '1 minute' UNION ALL
SELECT '30 minutes' UNION ALL
SELECT '2 Hours 15 Minutes' UNION ALL
SELECT '8 Hours' UNION ALL
SELECT '4 Hours 30 Minutes' UNION ALL
SELECT '1 Hour'
    
SELECT CONVERT(CHAR(5), DATEADD(MINUTE, 60 * NULLIF(RTRIM(LTRIM(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(TimeInText, ' Hours ', '.'), ' Hours', '.'), ' Hour', '.00'), ' Minutes', ''), ' ', ''))), ''), 0), 108)
FROM @tabvar

在尝试转换 8 小时时,我被“8”卡住了。而不是“8”

【问题讨论】:

  • 1 分钟不是0.01 小时,而是0.016666~;我希望您将其四舍五入到0.02 或(可能更好)显示更多小数点。然而,真正的问题是,为什么要将时间段存储为varchar,而当有time 数据类型时,则存储为描述性文本?
  • 嗨@Larnu,1 分钟是 0.16666。嗯,这是来自遗留应用程序的数据,正在尝试清理混乱。
  • 这并不能解释为什么当0.02 更接近时,您将'1 minute' 转换为0.01
  • 你能为字符串定义一个精确的语法和语义吗?是否允许'2 Hour'(当单词应该是复数时)? '65 minutes'(超过一小时的分钟数)? 'Days'? 'Seconds'?几小时前的几分钟? 'Quarter hour'? ...在不知道规则的情况下,很难解析字符串。
  • 嗨@Larnu,1分钟是0.02。我会相应地更新原帖。

标签: sql-server tsql sql-server-2016


【解决方案1】:

漂亮。 T-SQL 的强项不是字符串操作,您选择将时间存储为描述性字符串充其量是一个有问题的设计选择。但是,我也觉得将值设置为 decimal 也是一个坏主意。您应该使用 time 数据类型。

也就是说,这适用于提供的示例数据:

SELECT tv.TimeInText,
       ISNULL(CONVERT(decimal(5,3),LEFT(tv.TimeInText,NULLIF(h.CI,0)-1)),0) + ISNULL((CONVERT(decimal(5,3),LEFT(s.m,NULLIF(m.CI,0)-1)) / 60),0) AS NumberOfHours
FROM @tabvar tv
     CROSS APPLY (VALUES(CHARINDEX('hour',tv.TimeInText)))h(CI)
     CROSS APPLY (VALUES(CHARINDEX(' ',tv.TimeInText,NULLIF(h.ci,0))))ws(ci)
     CROSS APPLY (VALUES(STUFF(tv.TimeInText,1,ISNULL(ws.ci,0),'')))s(m)
     CROSS APPLY (VALUES(CHARINDEX('minute',s.m)))m(CI);

或者不使用VALUES 使表达式易于阅读...(享受这个混乱?):

SELECT tv.TimeInText,
       ISNULL(CONVERT(decimal(5,3),LEFT(tv.TimeInText,NULLIF(CHARINDEX('hour',tv.TimeInText),0)-1)),0) + ISNULL((CONVERT(decimal(5,3),LEFT(STUFF(tv.TimeInText,1,ISNULL(CHARINDEX(' ',tv.TimeInText,NULLIF(CHARINDEX('hour',tv.TimeInText),0)),0),''),NULLIF(CHARINDEX('minute',STUFF(tv.TimeInText,1,ISNULL(CHARINDEX(' ',tv.TimeInText,NULLIF(CHARINDEX('hour',tv.TimeInText),0)),0),'')),0)-1)) / 60),0) AS NumberOfHours
FROM @tabvar tv;

db<>fiddle

【讨论】:

    【解决方案2】:
    select *, format(datepart(hour, _time) + datepart(minute, _time)/60., '0.##') as NumberOfHours
    from
    (
    select *, 
        timefromparts
        (
        left(TimeInText, charindex(' hour', TimeInText)), 
        substring(TimeInText, charindex('minute', TimeInText)-3, 3), 
        0, 0, 0
        ) as _time
    from @tabvar
    ) as t;
    

    【讨论】:

      【解决方案3】:

      另一种选择

      示例

      Select A.* 
            ,NewVal = convert(decimal(10,2),
                              case when Pos2 like 'Hour%' then try_convert(int,Pos1)+isnull(try_convert(decimal(10,2),Pos3),0)/60 
                              else try_convert(decimal(10,2),Pos1)/60 end
                             )
       From  YourTable A
       Cross Apply (
                      Select Pos1 = trim(JSON_VALUE(S,'$[0]'))
                            ,Pos2 = trim(JSON_VALUE(S,'$[1]'))
                            ,Pos3 = trim(JSON_VALUE(S,'$[2]'))
                            ,Pos4 = trim(JSON_VALUE(S,'$[3]'))
                       From  ( values ( '["'+replace(replace([Hours in text],'"','\"'),' ','","')+'"]' ) ) A(S)
                   ) B
      

      退货

      Hours in text       NewVal
      1 minute            0.02
      30 minutes          0.50
      2 Hours 15 Minutes  2.25
      8 Hours             8.00
      4 Hours 30 Minutes  4.50
      1 Hour              1.00
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-18
        • 2012-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多