我正在定期(每月)导入大量数据。在转换过程中,我将字符串拆分为多个列,但这不仅仅是一个简单的拆分。有一些逻辑可以决定字符串的哪个部分进入哪个字段。
我编写了一个内联函数,它将字符串分成多个部分,并为您提供指定索引处的值。
参数是:
例如:
如果字符串值为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
答案 0 :(得分: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;
答案 1 :(得分: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函数。
答案 2 :(得分:0)
如果字符串的各个部分对您希望对数据执行的操作至关重要,则可以选择将部分存储为单个列或相关表格,从而进一步规范化。
或者,如果您需要多次访问这些部件,那么返回单个部件的表值函数可以提高性能。
答案 3 :(得分:0)
如果您的字符串具有固定(或确定的最大)数量的部分,您可以创建一组变量,如@ part1,@ part2等(如果每个部分具有特定含义,则使用更好的名称)。使用您的函数填充变量一次,并使用变量而不是重新解析。
- 或 -
使用解析方法将您的字符串转换为一个简短的临时表或表变量,其中包含一个varchar
列和一个tinyint
标识列(主题上SO上有很多帖子 - 和here
是一篇很好的文章,面向csv,但很容易适应你的情况)。然后,您可以使用select
中的序列列来找到所需的字符串部分。