2017-08-17 62 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,'')