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