4

我正在定期(每月)导入大量数据。在转换过程中,我将一个字符串拆分为多个列,但这不仅仅是一个简单的拆分。有一点逻辑可以决定字符串的哪个部分进入哪个字段。

我编写了一个内联函数,它将字符串分成多个部分,并为您提供指定索引处的值。

参数是:

  1. 字符串值
  2. 分隔符
  3. 指数

例如:

如果字符串值是X4-728Z5-121-84gff并且您希望函数为您提供 121,那么您可以像这样调用该函数:

fn_MyFunc('X4-728Z5-121-84gff', '-', 3)

我的问题是这样的:

在我的导入查询中,特定字段值所需的索引取决于另一个索引处的值。如果索引 1 处的值 =X4那么我想要索引 3,否则索引 4。

在单个查询中,我调用此函数 4 或 5 次,具体取决于某些 case 语句的结果。

该功能基本上一遍又一遍地做同样的事情......但每次,我都会得到不同的索引。如何减少工作量,使得拆分字符串的辛苦工作只完成一次,并且在同一个查询中,我可以轻松获得不同的索引?

请记住,这是在从外部源导入数据的过程中,任何建议标准化或索引视图等的答案都无济于事。

编辑

我被要求发布我的查询:

SELECT
    ComplexString,
    CAST(fn_MyFunc(ComplexString, '-', 1) AS NVARCHAR(2)) AS LocationCode,
    CAST(fn_MyFunc(ComplexString, '-', 2) AS NVARCHAR(25)) AS CompanyCode,
    NULLIF(CASE
        WHEN fn_MyFunc(ComplexString, '-', 1) = 'R1' THEN NULL
        ELSE CAST(fn_MyFunc(ComplexString, '-', 3) AS INT)
    END, 0) AS ManagementType,
    CASE
        WHEN fn_MyFunc(ComplexString, '-', 1) = 'R1' THEN CAST(fn_MyFunc(ComplexString, '-', 3) AS VARCHAR(25))
        ELSE CAST(fn_MyFunc(ComplexString, '-', 4) AS NVARCHAR(25))
    END AS Network,
    .
    .
    .
FROM MyTable
4

4 回答 4

4

如果所有字符串的最大值为 4 部分,则您可以内联执行此操作,而不是您的函数:

SELECT PARSENAME(REPLACE(column, '-', '.'), 
  CASE WHEN (condition for 4th element) THEN 1 
       WHEN (condition for 3rd element) THEN 2
       WHEN (condition for 2nd element) THEN 3
       WHEN (condition for 1st element) THEN 4
   END
FROM ...

您还可以考虑:

(a) 将字符串的每个部分存储在单独的计算列中。您甚至可以对计算列进行持久化/索引。

(b) 首先分别存储字符串的各个部分——连接总是比拆分更容易。

编辑给定更新的查询

;WITH x AS
(
  SELECT ComplexString,
         p1 = LEFT(ComplexString, 2),
         p2 = dbo.fn_MyFunc(ComplexString, '-', 2),
         p3 = dbo.fn_MyFunc(ComplexString, '-', 3),    
         p4 = dbo.fn_MyFunc(ComplexString, '-', 4)
         -- , other columns
  FROM dbo.MyTable
)
SELECT
    ComplexString,
    p1 AS LocationCode,
    LEFT(p2, 25) AS CompanyCode,
    CASE WHEN p1 <> 'RI' THEN CONVERT(INT, LEFT(p3, 3)) ELSE 0 END 
      AS ManagementType,
    LEFT(CASE WHEN p1 = 'RI' THEN p3 ELSE p4 END, 25) AS Network
FROM x;
于 2012-06-02T16:48:17.320 回答
4

创建一个拆分函数,将您的字符串拆分为列,并在cross apply.

拆分为 5 列的函数可能如下所示。

alter function [dbo].[SplitString]
(
    @Value nvarchar(max),
    @Delim nchar(1)
)
returns table as return
(
    select substring(T.Value, 1, T1.P - 1) as C1,
           substring(T.Value, T1.P + 1, T2.P - T1.P - 1) as C2,
           substring(T.Value, T2.P + 1, T3.P - T2.P - 1) as C3,
           substring(T.Value, T3.P + 1, T4.P - T3.P - 1) as C4,
           substring(T.Value, T4.P + 1, T5.P - T4.P - 1) as C5
    from (select @Value+replicate(@Delim, 5)) as T(Value) 
      cross apply (select charindex(@Delim, T.Value)) as T1(P)
      cross apply (select charindex(@Delim, T.Value, T1.P + 1)) as T2(P)
      cross apply (select charindex(@Delim, T.Value, T2.P + 1)) as T3(P)
      cross apply (select charindex(@Delim, T.Value, T3.P + 1)) as T4(P)
      cross apply (select charindex(@Delim, T.Value, T4.P + 1)) as T5(P)
)

它会像这样使用。

select *
from YourTable as Y
  cross apply dbo.SplitString(Y.ColumnToSplit, '-') as S

该函数将为每一行调用一次,您可以使用C1, C2, C3, ...字段列表或 where 子句中的列,而无需重新调用 split 函数。

于 2012-06-02T17:29:23.857 回答
0

如果字符串的各个部分是您希望对数据执行的操作的核心,则可以通过将这些部分存储为单独的列或相关表中来进一步规范化。

或者,如果您需要多次访问这些部分,则返回各个部分的表值函数将使您能够提高性能。

于 2012-06-02T16:39:44.360 回答
0

如果您的字符串具有固定(或确定的最大)数量的部分,您可以创建一组变量,如@part1、@part2 等(如果每个部分都有特定的含义,则使用更好的名称)。使用您的函数填充变量一次,并使用变量而不是重新解析。

- 或者 -

使用解析方法将您的字符串转换为具有一varchar列和一个tinyint标识列的窄临时表或表变量(关于该主题有许多关于 SO 的帖子 - 是一篇不错的文章,面向 csv,但很容易适应你的情况)。然后,您可以使用 a 中的序列列select来定位您需要的字符串部分。

于 2012-06-02T17:15:10.383 回答