Sql 如何使用CharIndex/子字符串获取第三个字符串部分

Sql 如何使用CharIndex/子字符串获取第三个字符串部分,sql,sql-server,tsql,Sql,Sql Server,Tsql,每个人我都想把一个名字列分成4个不同的部分。到目前为止,所有名称部分都由空格“”分隔。我在@thirdString填充名称的第四部分(通常是后缀)时遇到了问题,我希望将其视为@fourthString。我将用不同长度的不同名称来运行这个。我只是以罗伯特·多布森·巴德为例。其他名称可以是两部分或更多部分 -- Code for parsing a name with multiple parts -- You should be able to copy and paste this into a

每个人我都想把一个名字列分成4个不同的部分。到目前为止,所有名称部分都由空格“”分隔。我在@thirdString填充名称的第四部分(通常是后缀)时遇到了问题,我希望将其视为@fourthString。我将用不同长度的不同名称来运行这个。我只是以罗伯特·多布森·巴德为例。其他名称可以是两部分或更多部分

-- Code for parsing a name with multiple parts
-- You should be able to copy and paste this into any MS-SQL Environment it doesn't use a certain table.

DECLARE     @nameString as varchar(max),
        @firstSpaceLoc as smallint,
        @secondSpaceLoc as smallint,
        @thirdSpaceLoc as smallint,
        @forthSpaceLoc as smallint,
        @firstString as varchar(max),
        @secondString as varchar(max),
        @thirdString as varchar(max),
        @fourthString as varchar(max) 


 -- Create some type of loop or case statement to run through the entire table. 
SET @nameString = 'Robert Dobson Bud jr'

SET @firstSpaceLoc = CHARINDEX(' ',@namestring,1)

SET @secondSpaceLoc = CHARINDEX(' ', @namestring, CHARINDEX(' ',@nameString,1)+1)

SET @thirdSpaceLoc = 
CASE
  WHEN CHARINDEX(' ', 
                          @namestring, 
                          CHARINDEX(' ',@nameString,1)+1) = 0 THEN 0
  WHEN CHARINDEX(' ', 
                          @namestring, 
                          CHARINDEX(' ',@nameString,1)+1) > 0 THEN
                                CHARINDEX(' ', @namestring, 
                                CHARINDEX(' ', @namestring, 
                                CHARINDEX(' ',@nameString,1)+1)+1)
END
SET @forthSpaceLoc =
CASE
WHEN CHARINDEX(' ', 
                          @namestring, 
                          CHARINDEX(' ',@nameString,1)+1) = 0 THEN 0
WHEN CHARINDEX(' ', 
                          @namestring, 
                          CHARINDEX(' ',@nameString,1)+1) > 0 THEN 0
WHEN CHARINDEX(' ', 
                          @namestring, 
                          CHARINDEX(' ',@nameString,1)+1) > 0 THEN
                            CHARINDEX(' ', 
@namestring, 
                                CHARINDEX(' ', @namestring,

CHARINDEX(' ', @nameString, 
                                CHARINDEX(' ',@nameString,1)+1)+1)+1)
END

SELECT

   @firstString = 
   CASE
        WHEN @firstSpaceLoc > 0 THEN LEFT(@nameString,CHARINDEX(' ',@namestring,1)-1)
        ELSE @nameString
   END,
   @secondString =   
   CASE
        WHEN @firstSpaceLoc = 0 THEN ''
        WHEN @secondSpaceLoc = 0 THEN 
                    RIGHT(@namestring, LEN(@namestring)- CHARINDEX(' ',@namestring,1))
        WHEN @secondSpaceLoc > 0 THEN
                    REPLACE     (
                    SUBSTRING   (
                                   @nameString, CHARINDEX(' ',@namestring,1)+1, CHARINDEX(' ', @namestring, CHARINDEX(' ',@nameString,1)+1) 
                                         - CHARINDEX(' ',@namestring,1)),' ',''
                                 )
        ELSE ''
  END,



                                     @thirdString =
  CASE
        WHEN @firstSpaceLoc = 0 OR @secondSpaceLoc = 0  THEN ''
        WHEN @secondSpaceLoc > 0 THEN
                    SUBSTRING   (
                                   @nameString,
                                   CHARINDEX(' ', @namestring, 
                                   CHARINDEX(' ',@nameString,1)+1),
                                   LEN(@nameString)
                                 )             
  END,
  @fourthString =
  CASE
        WHEN @firstSpaceLoc = 0 OR @secondSpaceLoc = 0 OR @thirdSpaceLoc = 0 THEN ''
        WHEN @secondSpaceLoc > 0 AND @thirdSpaceLoc = 0 THEN ''
        WHEN @thirdSpaceLoc > 0 THEN
                        SUBSTRING( 
                                    @nameString,
                                   CHARINDEX(' ', @namestring,
                                   CHARINDEX(' ', @namestring, 
                                   CHARINDEX(' ',@nameString,1)+1)+1),
                                   LEN(@nameString)
                                    )

 END

-- Report names
SELECT
        @nameString sourceString,
        @firstString [First string],
        @secondString [Second string],
        @thirdString [Third string],
        @fourthString [Fourth String]


我想去掉第三栏的jr。其目的是在名称的4个不同部分中包含4个不同的列

使用拆分功能,可以非常简单地安排

SELECT firstString  = MAX(CASE WHEN ItemNumber = 1 THEN Item END),
       secondString = MAX(CASE WHEN ItemNumber = 2 THEN Item END),
       thirdString  = MAX(CASE WHEN ItemNumber = 3 THEN Item END),
       fourthString = MAX(CASE WHEN ItemNumber = 4 THEN Item END)
FROM dbo.DelimitedSplit8K_LEAD( @nameString, ' ');
函数的代码最初是发布和解释的。但我在复制定义

CREATE FUNCTION [dbo].[DelimitedSplit8K_LEAD]  
--===== Define I/O parameters  
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))  
RETURNS TABLE WITH SCHEMABINDING AS  
 RETURN  
--===== "Inline" CTE Driven "Tally Table” produces values from 0 up to 10,000...  
     -- enough to cover VARCHAR(8000)  
 WITH E1(N) AS (  
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL   
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL   
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1  
                ),                          --10E+1 or 10 rows  
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows  
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max  
 cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front  
                     -- for both a performance gain and prevention of accidental "overruns"  
                 SELECT 0 UNION ALL  
                 SELECT TOP (DATALENGTH(ISNULL(@pString,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4  
                ),  
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)  
                 SELECT t.N+1  
                   FROM cteTally t  
                  WHERE (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0)   
                )  
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.  
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),  
        Item = SUBSTRING(@pString,s.N1,ISNULL(NULLIF((LEAD(s.N1,1,1) OVER (ORDER BY s.N1) - 1),0)-s.N1,8000))  
   FROM cteStart s  
;  

第三个字符串中出现“jr”的原因有点神秘。在代码的这一部分:

@thirdString = CASE
    WHEN @firstSpaceLoc = 0 OR @secondSpaceLoc = 0  THEN ''
    WHEN @secondSpaceLoc > 0 THEN
                SUBSTRING   (
                               @nameString,
                               CHARINDEX(' ', @namestring, 
                               CHARINDEX(' ',@nameString,1)+1),
                               LEN(@nameString)
                             )             
为什么对子字符串的第三个参数使用
LEN(@nameString)
?当然,这将返回字符串的其余部分,包括“Jr”。您显然知道在获取
@secondString
值时不要这样做,您怎么会不知道在获取
@thirdString
值时要这样做呢


要获取
@thirdString
,您需要使用与获取
@secondString

相同的技术,此脚本将完成此任务

DECLARE     @namestring as varchar(max)
        SET @namestring = 'Robert Dobson Bud jr'
        --SET @namestring = 'Robert Dobson'

        ;with cte as (
            select cast(0 as int) [start],CHARINDEX(' ',@namestring,0) [end] ,@namestring namestring
            union all
            select cast(cte.[end] as int) [start],CHARINDEX(' ',@namestring,cte.[end]+1) [end] ,@namestring namestring from cte where [end]>0
        ),cte2 as (
        select * ,ROW_NUMBER() over (order by cte.[start]) seq
        ,substring(@namestring,cte.[start]+1,(case when cte.[end]=0 then len(@namestring)+1 else cte.[end] end)-cte.[start]-1) part from cte
        )
        select 
         (select part from cte2 where seq=1) [First String]
        ,(select part from cte2 where seq=2) [Second String]
        ,(select part from cte2 where seq=3) [Third String]
        ,(select part from cte2 where seq=4) [Fourt String]
对于4个零件名称,结果如下所示

First String    Second String   Third String    Fourt String
Robert          Dobson          Bud         jr
First String    Second String   Third String    Fourt String
Robert          Dobson          NULL            NULL
对于2个零件名称,结果如下所示

First String    Second String   Third String    Fourt String
Robert          Dobson          Bud         jr
First String    Second String   Third String    Fourt String
Robert          Dobson          NULL            NULL

这是你想要的吗

DECLARE @Str VARCHAR(45) = 'Robert Dobson Bud jr';

WITH CTE AS
(
  SELECT Value V,
         'Str' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS VARCHAR(10)) RN
  FROM STRING_SPLIT(@Str, ' ')
)
SELECT *
FROM
     (
       SELECT *
       FROM CTE
     ) X
     PIVOT
     (
       MAX(V) FOR RN IN ([Str1], [Str2], [Str3], [Str4])
     ) P;
返回:

+--------+--------+------+------+
|  Str1  |  Str2  | Str3 | Str4 |
+--------+--------+------+------+
| Robert | Dobson | Bud  | jr   |
+--------+--------+------+------+

是的,先生,我知道这就是问题所在,但当我尝试应用与我在secondString中使用的相同逻辑时,它并没有正确出现。我得到一些第二个字符串文本,或者只是不正确的格式。你应该编辑你的问题,以显示你试图在第三个字符串中使用相同的逻辑,这样我们就可以调试为什么它不适合你。顺便说一下,通过使用变量而不是重复它们的计算,您可以使代码更易于阅读。换句话说,您可以简单地执行
@firstSpaceLoc+1