【问题标题】:time difference of comma-delimited values逗号分隔值的时间差
【发布时间】:2014-06-02 10:45:36
【问题描述】:

我的客户有一个要求。 Note Column的数据模式如下

:TT:  12:32,12:35  :TT:

:TT:  05:17,05:30  :TT:

:TT:  01:56,02:00  :TT:

:TT:  01:00,01:12  :TT:

我需要删除 :TT: 标记并从最后一个值中减去第一个值。 例如 12:35-12:32=00:03。

我已经申请了下面的代码

WITH CTE1 AS
(
    SELECT (LTRIM(RTRIM(REPLACE(CAST(Note as NVarchar(4000)),':tt:','')))) AS Note 
    FROM UD_Notes 
    WHERE Note like ':t%'
)
SELECT Note FROM CTE1

现在低于结果-

  01:00,01:12  
  01:56,02:00  
  05:17,05:30  
  12:32,12:35 

谁能帮我解决这个问题?

【问题讨论】:

  • 我认为您的意思是“第二个中的第一个值”,是吗?
  • 是的,史蒂夫,你是对的
  • 这些数字是什么意思?他们是一个时代吗?如果是,是分钟:秒还是小时:分钟?
  • 是时间小时:分钟
  • 注意字段是 TEXT 数据类型。

标签: sql-server string split datediff


【解决方案1】:

我有一个解决方案,可以为您提供如下内容:
3
13
4
12

注意:已将其更新为 DATEDIFF

    WITH CTE1 AS
    (
        SELECT (LTRIM(RTRIM(REPLACE(CAST(Note as NVarchar(4000)),':tt:','')))) AS Note 

        FROM UD_Notes  
        WHERE Note like ':t%'
    )
    SELECT  Note INTO #RESULT FROM CTE1


    SELECT        
    DATEDIFF(MINUTE, CONVERT(datetime, left(CONVERT(varchar(50), LEFT(Note, CHARINDEX(',', Note) - 1)), 19)), CONVERT(datetime, left(CONVERT(varchar(50), RIGHT(Note, CHARINDEX(',', Note) - 1)), 19)))
    FROM #RESULT

我已经这样测试过:

        CREATE TABLE #PRERESULT(
        Note text)

        INSERT INTO #PRERESULT (note)
        VALUES
        (':TT: 12:32,12:35 :TT:'),
        (':TT: 05:17,05:30 :TT:'),
        (':TT: 01:56,02:00 :TT:'),
        (':TT: 01:00,01:12 :TT:');


           WITH CTE1 AS
            (
                SELECT (LTRIM(RTRIM(REPLACE(CAST(Note as NVarchar(4000)),':tt:','')))) AS Note 

                FROM #PRERESULT  
                WHERE Note like ':t%'
            )
            SELECT  Note INTO #RESULT FROM CTE1


            SELECT 
            DATEDIFF(MINUTE, CONVERT(datetime, left(CONVERT(varchar(50), LEFT(Note, CHARINDEX(',', Note) - 1)), 19)), CONVERT(datetime, left(CONVERT(varchar(50), RIGHT(Note, CHARINDEX(',', Note) - 1)), 19)))
            FROM #RESULT

        DROP TABLE #PRERESULT
        DROP TABLE #RESULT

祝你有美好的一天

艾蒂安

【讨论】:

  • Msg 241, Level 16, State 1, Line 1 从字符串转换日期和/或时间时转换失败。
  • CONVERT(datetime,Convert(nvarchar(50),RIGHT(Note, CHARINDEX(',', Note) - 1))) -CONVERT(datetime,Convert(nvarchar(50),LEFT(注意,CHARINDEX(',', Note) - 1))) 试试这个
  • 得到相同的错误 GOB
  • 见上面我是如何测试它的,它就是这样工作的。我看不出区别
  • 从文本到日期时间的转换:CONVERT(datetime, left (CONVERT(varchar(50), @Field), 19))
【解决方案2】:

您可以使用一个用户定义的标量函数来接收字符串(甚至包括 ':TT:' 在内的整个字符串),并对其进行处理以返回所需的结果。

通过这种方式,您可以轻松地重复使用它并对其进行测试。

类似这样的东西:

CREATE FUNCTION dbo.TimeDiff(@value AS nvarchar(4000))
RETURNS NVARCHAR(5)
AS
BEGIN
    DECLARE @cleaned NVARCHAR(11)
    SET @cleaned = LTRIM(RTRIM(REPLACE(@value,':TT:','')))
    DECLARE @h1 int
    DECLARE @m1 int
    DECLARE @h2 int
    DECLARE @m2 INT
    DECLARE @t1 INT
    DECLARE @t2 int  
    SET @h1 = CAST(SUBSTRING(@cleaned,1,2) AS int)
    SET @m1 = CAST(SUBSTRING(@cleaned,4,2) AS int)
    SET @h2 = CAST(SUBSTRING(@cleaned,7,2) AS int)
    SET @m2 = CAST(SUBSTRING(@cleaned,10,2) AS int)
    SET @t1 = @h1 * 60 + @m1
    SET @t2 = @h2 * 60 + @m2
    DECLARE @diff INT
    DECLARE @diffh NVARCHAR(2)
    DECLARE @diffm NVARCHAR(2)
    SET  @diff = @t1 - @t2
    SET @diffh = RIGHT('0' + CAST(@diff / 60 AS NVARCHAR(2)),2)
    SET @diffm = RIGHT('0' + CAST(@diff % 60 AS NVARCHAR(2)), 2)
    RETURN @diffh + ':' + @diffm
END

你可以这样测试它:

 SELECT dbo.TimeDiff(':TT: 12:23,11:54 :TT:')

然后您可以轻松地在您选择的句子中使用此功能。当然,您可以修改实现以提高效率,或者修改计算的细节。

【讨论】:

    【解决方案3】:

    试试这个:

    select 
    right('00'+cast(cast(substring(ltrim(rtrim(replace(cast(Note as nvarchar(100)),':TT:',''))),7,2) as int) - cast(substring(ltrim(rtrim(replace(cast(Note as nvarchar(100)),':TT:',''))),1,2) as int) as varchar),2) 
    + ':' 
    + right('00'+cast(cast(substring(ltrim(rtrim(replace(cast(Note as nvarchar(100)),':TT:',''))),10,2) as int) -  cast(substring(ltrim(rtrim(replace(cast(Note as nvarchar(100)),':TT:',''))),4,2) as int) as varchar),2)
    from ud_notes where note like ':t%'
    

    细分:

    1. 将 ':TT:' 替换为空格。
    2. 修剪字符串以删除不必要的空格。
    3. 由于字符串将时间表示为 HH:MM,我们可以安全地假设生成的子字符串将始终采用 xx:xx,xx:xx 的形式,长度为 11。因此,我们可以硬编码我们得到的索引表示开始和结束时间的小时和分钟的子字符串。
    4. 将字符串转换为整数并执行减法。
    5. 用必要数量的零填充。
    6. 与分隔符连接以将预期输出返回为varchar。

    【讨论】:

    • Msg 245,级别 16,状态 1,行 1 将 nvarchar 值“0”转换为数据类型 int 时转换失败。收到此错误。
    • 您是否遇到过字符串不是 xx:xx,xx:xx 格式的情况?该查询似乎适用于您的示例字符串
    • No Shree 数据没有 xx:xx,xx:xx 以外的值。
    • 嗯,不知道出了什么问题。我在这里设置了一个演示,也许你可以检查任何有问题的值? rextester.com/ONMM5371
    • Note字段是TEXT数据类型。这可能是个问题。
    【解决方案4】:
    select cast(dateadd(minute, 
                        datediff(minute, 
                                substring(Note, 7, 5), 
                                substring(Note, 13, 5)
                               ),
                        0) as time(0))
    

    结果:

    00:03:00
    00:13:00
    00:04:00
    00:12:00
    

    SQL Fiddle

    【讨论】:

      【解决方案5】:

      测试数据

      DECLARE @TABLE TABLE (Note TEXT)
      INSERT INTO @TABLE VALUES 
      (':TT:  12:32,12:35  :TT:'),
      (':TT:  05:17,05:30  :TT:'),
      (':TT:  01:56,02:00  :TT:'),
      (':TT:  01:00,01:12  :TT:')
      

      查询

      ;WITH CTE1 AS
      (
          SELECT  CAST(REPLACE(LEFT(Note, CHARINDEX(',', Note) -1),':tt:','') AS TIME) AS StartTime
                 ,CAST(SUBSTRING(Note, CHARINDEX(',', Note)+ 1, 5) AS TIME)     AS  EndTime
          FROM (SELECT CAST(Note AS VARCHAR(1000)) AS Note FROM @TABLE) A
          WHERE Note like ':t%'
      )
      SELECT CAST(StartTime AS NVARCHAR(5)) AS StartTime
            ,CAST(EndTime AS NVARCHAR(5))   AS EndTime
            ,DATEDIFF(MINUTE, StartTime,EndTime) TimeDifference
      FROM CTE1
      

      结果集

      ╔═══════════╦═════════╦════════════════╗
      ║ StartTime ║ EndTime ║ TimeDifference ║
      ╠═══════════╬═════════╬════════════════╣
      ║ 12:32     ║ 12:35   ║              3 ║
      ║ 05:17     ║ 05:30   ║             13 ║
      ║ 01:56     ║ 02:00   ║              4 ║
      ║ 01:00     ║ 01:12   ║             12 ║
      ╚═══════════╩═════════╩════════════════╝
      

      Working SQL FIDDLE

      【讨论】:

      • 参数数据类型文本对于左函数的参数 1 无效。
      • @Nishant 现在看看你应该在你的问题中提供了这些信息。无论如何,您需要做的就是将其转换为 varchar/nvarchar 数据类型,它应该可以正常工作。查看我的更新。
      【解决方案6】:

      我花了一段时间,我认为这不是最有效的方法(转换太多),但我有一个 XML 解决方案可以工作,有人可能会对其进行改进。请注意,由于您正在处理时间,因此我使用了 Date 函数 - 但请确保您阅读了最后的警告。基本上,在您的 CTE 中,您可以将数据转换为简单的 XML 格式,例如

      <Note>
          <T1>00:00</T1>
          <T2>00:00</T2>
      </Note>
      

      这消除了执行字符串拆分功能的需要。现在您可以通过使用DATEDIFF、DATEADD、CAST 和LEFT 的组合来获得结果

       WITH CTE1 AS
      (
          SELECT CAST('<Note><T1>' + REPLACE((LTRIM(RTRIM(REPLACE(CAST(Note AS NVARCHAR(4000)),
               ':tt:','')))), ',', '</T1><T2>') + '</T2></Note>' AS XML) AS Note 
          FROM UD_Notes 
          WHERE Note like ':t%'
      )
      
      
      SELECT LEFT(CAST(DATEADD(mi, DATEDIFF(mi, CAST(y.T1 AS TIME), CAST(y.T2 AS TIME)), CAST('00:00' AS TIME)) AS VARCHAR(20)), 5)
      FROM (
        SELECT c.value('(T1/text())[1]', 'varchar(50)') AS T1, 
              c.value('(T2/text())[1]', 'varchar(50)') AS T2
      FROM  (SELECT Note FROM CTE1) x
      CROSS APPLY Note.nodes('/Note') AS T(c)) y
      

      发生的情况是,首先我们让 CTE 给我们一个 XML 数据类型,然后我们可以查询它给我们两个“列”(T1 和 T2)。 SELECT 正在同时做很多工作,所以我会分解它。让我们假设您给出的示例是12:35 - 12:32 = 00:03。

      DATEDIFF(mi, CAST(y.T1 AS TIME), CAST(y.T2 AS TIME))
      

      这里我们得到T1 和T2 两列,我们CAST 那些TIME 类型并得到差异(即T2 - T1)。这给了我们一个 INT 与 3 的差异,所以在接下来的部分中,我将简单地将 3 替换为相关部分。

      所以,现在我们得到

      DATEADD(mi, 3, CAST('00:00' AS TIME))
      

      我们在这里所做的是创建一个名义上的 TIME 和 00:00 并在几分钟内添加我们的差异 (mi) 所以这给了我们 00:03。再一次,我们将其替换。

      CAST(00:03 AS VARCHAR(20))
      

      这里很简单,我们只是得到一个VARCHAR 表示我们的时间。因为TIME 的准确度非常好,所以我们得到秒和纳秒,看起来像00:03:00.0000000。我们想去掉秒和纳秒,因为我们在这里处理小时和分钟。

      LEFT('00:03:00.0000000', 5)
      

      这给我们留下了'00:03' 作为字符串。

      我不会费心浏览查询的主体,因为虽然我可以编写它,但我认为我不能足够清楚地解释它,但是有很多页面可以比我更好地解释 XML 查询,例如this blog post 来自 MSDN,this blog post 着眼于在 t-sql 中查询 XML 字段。

      我毫不怀疑有更好的方法可以做到这一点,这里的人也可以很好地解释查询 - 请随时添加到这里并解释我的努力。

      警告

      如果T1 是01:00 并且T2 是12:57 那么你会得到11:57 的答案,因为它们在前进方向上确实相隔11 小时57 分钟。老实说,我现在还没有时间研究如何让这两次得到 3 的结果,但我希望其他人可能知道如何做。

      【讨论】:

      • 感谢 steve 提供详细的方法。但我遇到错误 - 从字符串转换日期和/或时间时转换失败。
      • 不用担心。有很多选项可供选择,但我觉得为了完整起见可能值得添加它,因为它是另一种可能的途径。祝你好运!
      • 我使用的是 SQL Server 2008R2
      • 嗯,它肯定会起作用——这就是我用的。只是可能不一定是最适合您的解决方案 - 您有几个可供选择!
      【解决方案7】:

      嗨 Nishant 试试这个:

      select DATEDIFF(MI,SUBSTRING(REPLACE(Note,':TT:',''),  
          charindex('',REPLACE(Note,':TT:','')),  
          charindex(',',REPLACE(Note,':TT:',''))),  
          SUBSTRING(REPLACE(Note,':TT:',''),  
          charindex(',',REPLACE(Note,':TT:',''))+1,  
          len(REPLACE(colval,':TT:',''))-charindex(',',REPLACE(Note,':TT:',''))))  
      
      from UD_Notes
      

      【讨论】:

      • 嗨,我的 Coloumn 字段是 TEXT 数据类型。
      【解决方案8】:

      如果你想得到 hh:mi 格式的结果:

      SELECT
          CONVERT(VARCHAR(5), DATEADD(minute, DATEDIFF(minute, LEFT(LTRIM(REPLACE(CONVERT(VARCHAR(8000), Note), ':TT:', '')), 5), RIGHT(RTRIM(REPLACE(CONVERT(VARCHAR(8000), Note), ':TT:', '')), 5)), 0), 14)
      FROM
          UD_Notes
      WHERE
          PATINDEX(':T%', Note) > 0
      

      说明:提取左右时间字符串。将字符串隐式转换为时间数据,同时获取以分钟为单位的整数差。将结果整数转换为 hh:mi。

      【讨论】:

        【解决方案9】:

        嗯,所有答案都非常正确,我必须选择其中一个。 不幸的是,我在结果集中得到了空格,因为这些空格我得到了转换错误(varchar to time)。 我通过以下查询克服了问题,它现在对我有用。 感谢所有资深成员和专家为我提供宝贵的意见。 我得到了我想要的结果的正确方法。

        {    
        SELECT 
        CONVERT(VARCHAR,DATEDIFF(mi,
        CAST(SUBSTRING(REPLACE(CAST(Note AS VARCHAR(1000)),':TT:',''),CHARINDEX(':',REPLACE(CAST(Note AS VARCHAR(1000)),':TT:',''))-2,CHARINDEX(':',REPLACE(CAST(Note AS VARCHAR(1000)),':TT:',''))) AS TIME)
        ,CAST(SUBSTRING(REPLACE(CAST(Note AS VARCHAR(1000)),':TT:',''),CHARINDEX(',',REPLACE(CAST(Note AS VARCHAR(1000)),':TT:',''))+1,5) AS Time))) + ' mins' As 'TimeDiff'
         FROM UD_Notes where Note like '%:TT:%'    }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-15
          • 1970-01-01
          • 2015-12-03
          • 1970-01-01
          • 1970-01-01
          • 2015-08-24
          相关资源
          最近更新 更多