以逗号分隔的值的时差

时间:2014-06-02 10:45:36

标签: sql-server string split datediff

我的客户要求。注释列

的数据模式如下
: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:tag并从最后一个减去第一个值。 例如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 

有人可以帮我解决这个问题吗?

9 个答案:

答案 0 :(得分:2)

我有一个解决方案可以给你这样的东西:
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

度过愉快的一天

艾蒂安

答案 1 :(得分:1)

试试这个:

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

答案 2 :(得分:1)

您可以使用接收字符串的标量用户定义函数(甚至包括':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 :(得分:1)

测试数据

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

答案 4 :(得分:1)

嗨,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

enter image description here

答案 5 :(得分:1)

如果你想得到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。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

我花了一段时间,而且我认为这不是最有效的方式(转换次数太多),但我有一个XML解决方案正在运行,有人可能会改进。请注意,由于您处理的时间我使用了日期函数 - ,但请务必阅读最后的警告。基本上,在您的CTE中,您将数据转换为简单的XML格式,如

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

这消除了进行字符串拆分功能的需要。现在,您可以使用DATEDIFFDATEADDCASTLEFT

的组合来获得结果
 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数据类型,然后我们可以查询这些数据类型,为我们提供两个“列”(T1T2)。 SELECT一次做了很多工作,所以我会把它分解。让我们假设您提供的示例为12:35 - 12:32 = 00:03

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

在这里,我们得到两列T1T2以及CAST两列TIME类型并获得差异(即T2 - T1)。这给我们INT 3的差异,因此在下一位我只需将3替换为相关部分。

所以,现在我们得到了

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

我们在这里所做的是创建TIME 00:00的{​​{1}}并在几分钟内添加我们的差异(mi),这样就会给我们00:03。再一次,我们将替换它。

CAST(00:03 AS VARCHAR(20))

这里很简单,我们只是得到VARCHAR代表我们的时间。因为TIME具有非常好的准确性,所以我们得到的秒和纳秒看起来像00:03:00.0000000。我们想要摆脱秒和纳秒,因为我们在这里处理小时和分钟。

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

我们将'00:03'作为字符串留给我们。

我不打算通过查询的主体,因为虽然我可以编写它,但我认为我不能很清楚地解释它,但是有很多页面可以解释XML查询远比我更好来自MSDN的this blog post和查看t-sql中查询XML字段的this blog post

我毫不怀疑有一个更好的方法可以做到这一点,这里的人也可以对查询给出一个很好的解释 - 请任何人都可以自由添加并解释我的努力。

<强> CAVEAT

如果T101:00T212:57,那么您将得到11:57的答案,因为它们确实相隔11小时57分钟向前的方向。说实话,我现在没有时间研究如何让这两次给你3的结果,但是其他人可能会发现如何,我希望。

答案 8 :(得分:0)

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

{    
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:%'    }