【问题标题】:Convert varchar time (for time > 24 hours) to float将 varchar 时间(时间 > 24 小时)转换为浮点数
【发布时间】:2016-10-06 07:19:36
【问题描述】:

我有一列时间记录表示两个日期之间的差异。其中一些记录超过 24 小时。

由于时间语法不考虑 > 24 小时的时间记录,我不得不将这些记录转换为 varchar hh:mm:ss,如下面链接中的解决方案所述:

SQL date format [h]:mm:ss like Excel does, beyond 24 hr

这很好用,但我的问题是我现在需要将它们转换为浮点数(例如 69:00:00.0000 为 2.875)。

很遗憾,我不能使用通常建议的 datediff 来执行此操作,因为它会为超过 24 小时的记录引发“超出范围”错误。

关于如何克服这个问题的任何想法?

【问题讨论】:

  • I've had to convert these records to varchar ...我认为永远将数字数据存储为varchar 不是一个好主意。有没有机会在几秒钟内存储差异?
  • 只需将持续时间存储为一个数字,存储经过的秒/分钟/天/年,任何适合您需要的测量单位(即我不会以秒为单位测量地质年龄,我也不会测量100M 冲刺数小时)。如果您需要使用 hh:mm:ss 格式以小时、分钟和秒为单位显示此数字,那么这是表示层的工作。将其存储为字符串,因为最终您想以某种方式显示它是一个非常糟糕的主意。
  • 另一种选择是存储您的开始日期和时间以及结束日期和时间,然后您可以使用DATEDIFF 轻松计算出您喜欢的任何单位的持续时间。相关阅读见Bad habits to kick : choosing the wrong data type
  • 由于您是新来的(顺便说一句:欢迎!),请给我一个提示:您在(最佳)答案的投票计数器下方勾选接受检查,真是太好了。这将 1) 将此问题标记为已解决 2) 让追随者更容易找到最佳解决方案 3) 向回答者支付积分和 4) 向您支付积分。由于您自己已经越过了 15 点边界,因此您还被要求对贡献进行投票。这是说谢谢的方式。编码快乐!

标签: sql sql-server datetime sql-date-functions sqldatetime


【解决方案1】:

感谢有用的帖子,我接受了原始 cmets 的建议,因为将日期之间的差异计算为数字并稍后在表示层 (Excel) 中进行转换要容易得多。

为此,我使用 DATEPART 逻辑将日、时、分、秒相加,得出“十进制日”数字,然后使用 Excel 将其转换为 [h]:mm:ss

(例如,'2016-04-30 23:23:00' 和 '2016-04-30 23:25:00' 之间的差异是 2 分钟。这是 0.0013888833 作为十进制日,转换为 0:02 :00 在 Excel 中格式化为 [h]:mm:ss)

很遗憾,我没有时间测试提供的替代解决方案是否有效。

【讨论】:

  • 我什至不会费心测试其他解决方案 - 虽然它们可能有效,但它们会让我想起问题的答案 - Pounding A Nail: Old Shoe or Glass Bottle?,事实是虽然两者都可能有效,但两者都在治疗症状,而不是实际问题。你的方法已经纠正了这个问题(这在 SO 上实际上很少见,而且相当令人耳目一新 - 这样的建议通常意味着为什么不能改变系统的弱借口)
  • @GarethD 关于 SO 的大量问题就像您发布的文章中的问题一样,我总是看到 cmets 建议构建一个良好的正常 (NF) 解决方案(不要将逗号分隔值存储在单行等)。答案一如既往 - 是的,我们知道它很糟糕,不,我们不能重建它。基本上我们公司也有同样的情况。这就是为什么,大多数时候,我回答这样的问题只是为了好玩,而为了做一些我还没有做过的东西。像OP给出的答案非常罕见(在列表中我发现很少),值得一提!这只是我的观点。 :)
【解决方案2】:

这样的?

DECLARE @YourTime VARCHAR(100)='69:00:00.0000';

WITH Splitted AS
(
    SELECT @YourTime AS t
          ,CHARINDEX(':',@YourTime)-1 AS HourLength
          ,LEFT(@YourTime,CHARINDEX(':',@YourTime)-1) AS HourPart
)
SELECT HourPart/24 + CAST(CAST(CAST(STUFF(@YourTime,1,HourLength,HourPart-(HourPart/24)*24) AS TIME) AS DATETIME) AS FLOAT)
FROM Splitted

UPDATE同函数

CREATE FUNCTION dbo.ConvertExceedingTimeToFloat(@TimeString VARCHAR(100))
RETURNS FLOAT
AS
BEGIN
    DECLARE @RetVal FLOAT;
    WITH Splitted AS
    (
        SELECT @TimeString AS t
              ,CHARINDEX(':',@TimeString)-1 AS HourLength
              ,LEFT(@TimeString,CHARINDEX(':',@TimeString)-1) AS HourPart
    )
    SELECT @RetVal = HourPart/24 + CAST(CAST(CAST(STUFF(@TimeString,1,HourLength,HourPart-(HourPart/24)*24) AS TIME) AS DATETIME) AS FLOAT)
    FROM Splitted;

    RETURN @RetVal;
END
GO

SELECT dbo.ConvertExceedingTimeToFloat('69:00:00.0000')
GO

DROP FUNCTION dbo.ConvertExceedingTimeToFloat;

【讨论】:

    【解决方案3】:

    也许你可以 REPLACE :.。这将为您提供一个可以用 PARSENAME 解析的字符串(从 SQL Server 2012 开始),然后 CAST 浮动:

    DECLARE @SomeTime VARCHAR(100)='69:00:00.0000'
    
    SELECT CAST(PARSENAME(REPLACE(@SomeTime,':','.'),4)/24.00 as float)
    

    或者SUBSTRINGCHARINDEX

    SELECT CAST(SUBSTRING(@SomeTime,1,CHARINDEX(':',@SomeTime)-1)/24.00 as float)
    

    输出:

    2,875
    

    希望我没听错。

    编辑

    上述方法只使用了几个小时。如果您需要更深入:

    DECLARE @SomeTime VARCHAR(100)='69:55:10.999',
            @x xml
    --Convert to XML
    SELECT @x = CAST('<p>'+REPLACE(REPLACE(@SomeTime,':','.'),'.','</p><p>') +'</p>' as xml)
    --Working with XML, each part need convertion
    SELECT  CAST(
            t.c.value('/p[1]','int')/24.00+
            (t.c.value('/p[2]','int')/60.00)/24.00+
            ((t.c.value('/p[3]','int')/60.00)/60.00)/24.00+
            (((t.c.value('/p[4]','int')/1000.00)/60.00)/60.00)/24.00
            as float) result
    FROM @x.nodes('/') as t(c)
    

    输出:

    2,9133217194375
    

    注意:

    我对 SQL Server 中的数学知之甚少,如果您在当前解决方案中看到任何流程,请报告/建议。

    【讨论】:

    • 顺便说一句:值得一提的是,PARSENAME 需要 SQL Server 2012+
    • @Shnugo 修复了 PARSENAME 并添加了 SUBSTRING 解决方案。您还提到了哪些其他部分?
    • 如果给定值有分钟,这将被忽略...您的解决方案仅适用于几个小时...
    • @Shnugo 我没有看到问题中的任何其他部分 - 没有提到要使用的分钟和秒,所以我只需要几个小时。如果 OP 需要这些东西 - 我想,他会在这里添加评论,我将删除/重写我的解决方案。
    • 好吧,我们不知道...但是如果值是裸小时,为什么 OP 必须将这些记录转换为 varchar hh:mm:ss
    猜你喜欢
    • 2012-04-09
    • 2021-02-16
    • 1970-01-01
    • 2013-10-14
    • 2012-12-01
    • 1970-01-01
    • 2018-12-23
    • 1970-01-01
    相关资源
    最近更新 更多