2

背景
我有一个字符串,最多可以包含五个不同的时间,用空格分隔。该字符串是将后端数据库中的字段导出到数据仓库 (SQL Server 2008 R2)。

 Back end database          ->  Data warehouse string
 [LF] = line feed code
+========+================+
|Company |SLA_Times       |
+========+================+
|ABC01   |                | ->  NULL
+--------+----------------+
|DEF01   |00:30:00[LF]    |
|        |[LF]            | ->  '00:30:00  1 08:00:00'
|        |1 08:00:00      |
+--------+----------------+
|GHI01   |00:15:00[LF]    |
|        |01:00:00[LF]    |
|        |01:00:00[LF]    | ->  '00:15:00 01:00:00 01:00:00 04:00:00 08:00:00'
|        |04:00:00[LF]    |
|        |08:00:00        |
+--------+----------------+
|JKL01   |08:00:00[LF]    |
|        |21:00:00[LF]    |
|        |4 09:00:00[LF]  | ->  '08:00:00 21:00:00 4 09:00:00 10 00:00:00 100 00:00:00'
|        |10 00:00:00[LF] |
|        |100 00:00:00    |
+--------+----------------+
|MNO01   |[LF]            |
|        |[LF]            | ->  '   16:00:00'
|        |[LF]            |
|        |16:00:00        |
+--------+----------------+

我不被允许发布图片,所以我不得不构建上面的代码。我打算包括下面的图片,所以也许它有助于更​​清楚地看到事情:

数据库到字符串

SLA_TIMES 字段最多包含五个时间指示器,由换行符分隔。字段中的时间顺序对应于可以设置 SLA 时间的五个优先级 (1-5)。这个顺序当然反映在字符串中。如您所见,de SLA_TIMES 字段中的换行符被转换为空格。

每个时间指示器可以以两种方式出现:

  • 要么只有时间部分,要么
  • 有一个自然日部分和一个时间部分,由一个空格隔开。

像这样:

'00:30:00'   indicates 30 minutes
'4 09:00:00' indicates 4 natural days (4 x 24 hours) plus 9 hours (total 105 hours)

我在数据库中看到的最大自然天数是9999,但谁知道他们将来输入了什么。;-)


我需要的目标:

  • 从字符串中提取时间指示符,例如 '00:30:00 02:00:00 2 16:00:00'
  • 将它们转换为分钟和
  • 将它们放在五个变量中,命名为@SLA_1 到@SLA_5。

如果字符串中没有设置时间(或者没有字符串并且该字段为 NULL),它将在变量中设置为 0。(在这种情况下,将使用默认的 SLA 时间。)

例如,对于上图中的公司 ABC01,值将是:

@SLA_1 = 0
@SLA_2 = 0
@SLA_3 = 0
@SLA_4 = 0
@SLA_5 = 0

对于公司 DEF01,值将是:

@SLA_1 = 30
@SLA_2 = 0
@SLA_3 = 1920
@SLA_4 = 0
@SLA_5 = 0

对于 GHI01 公司,值将是:

@SLA_1 = 15
@SLA_2 = 60
@SLA_3 = 60
@SLA_4 = 240
@SLA_5 = 480

对于公司 JKL01,值将是:

@SLA_1 = 480
@SLA_2 = 1260
@SLA_3 = 6300
@SLA_4 = 14400
@SLA_5 = 144000

对于公司 MNO01,值将是:

@SLA_1 = 0
@SLA_2 = 0
@SLA_3 = 0
@SLA_4 = 960
@SLA_5 = 0

这些变量将用于将 SLA 时间与工单的周转时间进行比较。

一些示例字符串是:

'00:30:00  1 08:00:00'
'00:15:00 01:00:00 01:00:00 04:00:00 08:00:00'
'08:00:00 21:00:00 4 09:00:00 10 00:00:00 100 00:00:00'
'   16:00:00'
'00:30:00 02:00:00   2 16:00:00'
'1 00:00:00 2 00:00:00 4 00:00:00 16 00:00:00 32 00:00:00'
' 02:00:00   9999 08:00:00'

到目前为止所采取的步骤
现在我对 SQL 不是那么精通,而且我已经为如何完成这个问题摸索了将近一个星期。我试图想出一些使用 CHARINDEX 和 SUBSTRING 的东西,但无法将我的大脑包裹起来。我知道如何将时间转换为分钟

SELECT DATEDIFF(minute,'00:00:00','03:00:00')

但这并没有让我走得很远。

任何帮助将不胜感激!

4

1 回答 1

0

您可以使用这个部分解决方案,它创建一个包含以下列的recorset IndexNaturalDaysTime

DECLARE @Txt NVARCHAR(4000);
SET @Txt = 
    N'00:15:00' + CHAR(10) + 
    '01:00:00' + CHAR(10) + 
    '01:00:00' + CHAR(10) + 
    '04:00:00' + CHAR(10) + 
    '123 08:00:00';

DECLARE @IndexSeparator1 INT, 
    @IndexSeparator2 INT,
    @IndexSeparator3 INT,
    @IndexSeparator4 INT;

SET @IndexSeparator1 = NULLIF( CHARINDEX(CHAR(10) ,@Txt), 0); 
SET @IndexSeparator2 = NULLIF( CHARINDEX(CHAR(10) ,@Txt, @IndexSeparator1+1), 0); 
SET @IndexSeparator3 = NULLIF( CHARINDEX(CHAR(10) ,@Txt, @IndexSeparator2+1), 0); 
SET @IndexSeparator4 = NULLIF( CHARINDEX(CHAR(10) ,@Txt, @IndexSeparator3+1), 0); 

SET @IndexSeparator1 = CASE WHEN @IndexSeparator1 IS NULL AND @IndexSeparator2 IS NULL THEN 4001 ELSE @IndexSeparator1 END
SET @IndexSeparator2 = CASE WHEN @IndexSeparator1 <> 4001 AND @IndexSeparator2 IS NULL AND @IndexSeparator3 IS NULL THEN 4000 ELSE @IndexSeparator2 END
SET @IndexSeparator3 = CASE WHEN @IndexSeparator2 <> 4001 AND @IndexSeparator3 IS NULL AND @IndexSeparator4 IS NULL THEN 4000 ELSE @IndexSeparator3 END

SELECT  
    z.Idx,
    CONVERT(INT, CASE WHEN z.TimeSeparator > 0 THEN LEFT(z.Value, z.TimeSeparator-1) END) AS NaturalDays,
    CONVERT(TIME(0), -- or DATETIME
    NULLIF(CASE 
        WHEN z.TimeSeparator > 0 THEN SUBSTRING(z.Value, z.TimeSeparator + 1, 4000)  
        WHEN z.TimeSeparator = 0 THEN z.Value
        ELSE ''
    END, '')) AS [Time]
FROM
(
    SELECT  *, PATINDEX('%[ ][0-9][0-9]:[0-9][0-9]:[0-9][0-9]', y.Value) AS TimeSeparator
    FROM
    (
        SELECT  x.Idx, LTRIM(RTRIM(x.Value)) AS Value
        FROM
        (
            SELECT 1 AS Idx, SUBSTRING(@Txt, 1, @IndexSeparator1 - 1) AS Value UNION ALL
            SELECT 2, SUBSTRING(@Txt, @IndexSeparator1 + 1, @IndexSeparator2 - @IndexSeparator1 - 1) UNION ALL
            SELECT 3, SUBSTRING(@Txt, @IndexSeparator2 + 1, @IndexSeparator3 - @IndexSeparator2 - 1) UNION ALL
            SELECT 4, SUBSTRING(@Txt, @IndexSeparator3 + 1, @IndexSeparator4 - @IndexSeparator3 - 1) UNION ALL
            SELECT 5, SUBSTRING(@Txt, @IndexSeparator4 + 1, 4000)
        ) x
    ) y
) z

结果:

Idx         NaturalDays Time
----------- ----------- --------
1           NULL        00:15:00
2           NULL        01:00:00
3           NULL        01:00:00
4           NULL        04:00:00
5           123         08:00:00

注意 #1:基于此示例,您可以创建一个内联函数(例如dbo.MyFunction)。

注意#2:您可以这样使用这个内联函数:

SELECT @VarDays1 = f.NaturalDays, @VarTime1 = f.[Time] 
FROM dbo.MyFunction(@param) AS f 
WHERE f.Idx = 1 -- for @SLA_1
于 2013-09-15T19:08:07.837 回答