2017-04-01 63 views

回答

4

任何分流/ parse函数会做的伎俩,但是您必须执行二级逻辑来清理已分析的字符串。也就是说,我修改了一个解析函数来接受任何两个不相似的分隔符(开始/结束)。在这种情况下,a和:

另外,作为表值函数,可以很容易地将其并入CROSS APPLY或作为独立的,如下所示。

Select NewString = Stuff((Select ',' +RetVal 
From [dbo].[udf-Str-Extract](@S,',',':') 
For XML Path ('')),1,1,'') 

返回

F11.20,F13.20,F14.10 

的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,'[[',']]') 
*/ 

编辑只是与可视化

帮助如果您执行单独的TVF:

declare @S varchar(200) = ',F11.20:,F13.20:Sedative, hypnotic o,F14.10:Cocaine abuse, uncom'; 

Select * From [dbo].[udf-Str-Extract](@S,',',':') 

返回

RetSeq RetPos RetVal 
1  2  F11.20 
2  10  F13.20 
3  38  F14.10 

EDIT 2 - 通过交叉执行应用

Declare @YourTable table (ID int,SomeString varchar(200)) 
Insert Into @YourTable values 
(1,',F11.20:,F13.20:Sedative, hypnotic o,F14.10:Cocaine abuse, uncom'), 
(2,',Z99.55:,Z25.10:Someother text') 

Select A.ID 
     ,B.* 
From @YourTable A 
Cross Apply (
       Select NewString = Stuff((Select ',' +RetVal 
              From [dbo].[udf-Str-Extract](A.SomeString,',',':') 
              For XML Path ('')),1,1,'') 
      ) B 

返回

ID NewString 
1 F11.20,F13.20,F14.10 
2 Z99.55,Z25.10 
+0

路比我试图做的更好,删除我的回答 –

+1

@WouterVanherck刚刚被这只狗咬过之前:) –

1

如果要提取文本总是在形式(字母,数字,数字,号码,数量),并总有3个实例该文本的,那么你可以这样做:

WITH 
s1(string, ci) AS (SELECT @S, CHARINDEX(':', @S)), 
s2(ci) AS (SELECT CHARINDEX(':', @S, ci+1) FROM s1), 
s3(ci) AS (SELECT CHARINDEX(':', @S, ci+1) FROM s2) 
SELECT 
    SUBSTRING(string, s1.ci-6, 6)+','+ 
    SUBSTRING(string, s2.ci-6, 6)+','+ 
    SUBSTRING(string, s3.ci-6, 6) 
FROM s1, s2, s3; 

执行计划:

enter image description here

它没有得到任何效率。

如果其始终的任何实例之前的6个字符“:”你可以抓住NGrams8K的副本,并做到这一点:

declare @S varchar(200) = ',F11.20:,F13.20:Sedative, hypnotic o,F14.10:Cocaine abuse, uncom'; 

SELECT NewString = STUFF 
    ((SELECT ','+SUBSTRING(@S, position-6, 6) 
    FROM dbo.NGrams8k(@S, 1) 
    WHERE token = ':' 
    FOR XML PATH('')),1,1,''); 

使用NGrams8K和可变的另一种方式:

declare @S varchar(200) = ',F11.20:,F13.20:Sedative, hypnotic o,F14.10:Cocaine abuse, uncom'; 
declare @newstring varchar(100)=''; 

declare @S varchar(200) = ',F11.20:,F13.20:Sedative, hypnotic o,F14.10:Cocaine abuse, uncom'; 
declare @newstring varchar(100)=''; 

SELECT 
    @newstring += 
    CASE @newstring WHEN '' THEN '' ELSE ',' END +SUBSTRING(@S, position-6, 6) 
FROM dbo.NGrams8k(@S, 1) 
WHERE token = ':'; 

SELECT @newstring;