2017-08-17 63 views
2

我有一个varchar(max)列以下字符串:SQL查询:在LONG VARCHAR删除多个字符的字符串(max)列

PREV - FirstName: John/LAST - FirstName: Johan; PREV- LastName: Crescot/LAST - LastName: Crescott; 

每一个分号后可以来无穷无尽的上一个值和最终值取决于源系统中所做更改的数量。

我需要编写一个只返回PREV值的查询。在上面的字符串的情况下,所期望的结果将是:

FirstName: John; LastName: Crescot 

所有斜杠(/)分隔符和破折号需要也被删除,你可以在需要的结果看。

任何人都可以帮助我吗?谢谢你们!

回答

1

如果开放给UDF,请考虑以下内容。

厌倦了提取字符串(charindindex,patindex,left,right ...),我修改了一个解析函数来接受两个不相似的参数。在这种情况下一个 'PREV' 和 '/'

Declare @YourTable table (ID int,SomeCol varchar(max)) 
Insert Into @YourTable values 
(1,'PREV - FirstName: John/LAST - FirstName: Johan; PREV- LastName: Crescot/LAST - LastName: Crescott;') 

Select A.ID 
     ,B.NewVal 
From @YourTable A 
Cross Apply (
       Select NewVal = Stuff((Select '; '+ltrim(rtrim(replace(RetVal,'-',''))) 
             From [dbo].[udf-Str-Extract](A.SomeCol,'PREV','/') 
             For XML Path ('')),1,2,'') 
      ) B 

返回

ID NewVal 
1 FirstName: John; LastName: Crescot 

的UDF如果有意

CREATE FUNCTION [dbo].[udf-Str-Extract] (@String varchar(max),@Delimiter1 varchar(100),@Delimiter2 varchar(100)) 
Returns Table 
As 
Return ( 

with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)), 
     cte2(N) As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 N1,cte1 N2,cte1 N3,cte1 N4,cte1 N5,cte1 N6) A), 
     cte3(N) As (Select 1 Union All Select t.N+DataLength(@Delimiter1) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter1)) = @Delimiter1), 
     cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter1,@String,s.N),0)-S.N,8000) From cte3 S) 

Select RetSeq = Row_Number() over (Order By N) 
     ,RetPos = N 
     ,RetVal = left(RetVal,charindex(@Delimiter2,RetVal)-1) 
From (
     Select *,RetVal = Substring(@String, N, L) 
     From cte4 
     ) A 
Where charindex(@Delimiter2,RetVal)>1 

) 
/* 
Max Length of String 1MM characters 

Declare @String varchar(max) = 'Dear [[FirstName]] [[LastName]], ...' 
Select * From [dbo].[udf-Str-Extract] (@String,'[[',']]') 
*/ 
0
create table #temp(val varchar(max)) 

Insert into #temp values('PREV - FirstName: John/LAST - FirstName: Johan; PREV - LastName: Crescot/LAST - LastName') 

Select stuff(
(SELECT ';'+ 
    Replace(stuff(Tbl.Col.value('./text()[1]','varchar(50)'),charindex('/',Tbl.Col.value('./text()[1]','varchar(50)')),len(Tbl.Col.value('./text()[1]','varchar(50)')),''),'PREV -','')as ColName 
FROM 
(Select cast('<a>'+ replace((SELECT val As [*] FOR XML PATH('')), ';', '</a><a>') + '</a>' as xml)as t 
from #temp) tl 
Cross apply 
tl.t.nodes('/a') AS Tbl(Col) for xml path(''),type).value('.','NVARCHAR(MAX)'),1,2,'') 

此方法不需要任何额外的UDF。 分解上述查询以便于理解: 1.将一行字符串转换为基于分号';'的多行

SELECT 
Tbl.Col.value('./text()[1]','varchar(50)') 
FROM 
(Select cast('<a>'+ replace((SELECT val As [*] FOR XML PATH('')), ';', '</a><a>') + '</a>' as xml)as t 
    from #temp) tl 
Cross apply 
tl.t.nodes('/a') AS Tbl(Col) 

2.Over上述提取的值,则使用替换和东西命令来删除不必要的字符

 SELECT 
    Replace(stuff(Tbl.Col.value('./text()[1]','varchar(50)'),charindex('/',Tbl.Col.value('./text()[1]','varchar(50)')),len(Tbl.Col.value('./text()[1]','varchar(50)')),''),'PREV -','')as ColName 
FROM 
(Select cast('<a>'+ replace((SELECT val As [*] FOR XML PATH('')), ';', '</a><a>') + '</a>' as xml)as t 
    from #temp) tl 
Cross apply 
tl.t.nodes('/a') AS Tbl(Col) 

3.使用的东西和XML路径,使多个行回到由分开的单个行根据需要使用分号

 Select stuff(
(SELECT ';'+ 
Replace(stuff(Tbl.Col.value('./text()[1]','varchar(50)'),charindex('/',Tbl.Col.value('./text()[1]','varchar(50)')),len(Tbl.Col.value('./text()[1]','varchar(50)')),''),'PREV -','')as food_Name 
FROM 
(Select cast('<a>'+ replace((SELECT val As [*] FOR XML PATH('')), ';', '</a><a>') + '</a>' as xml)as t 
    from #temp) tl 
Cross apply 
tl.t.nodes('/a') AS Tbl(Col) for xml path(''),type).value('.','NVARCHAR(MAX)'),1,2,'')