将字符串表达式解析为列
Parse a String Expression into Columns
我有一个字符串,例如 32,21C2L5N8C
存储在一个字段中。现在我想把这个字符串扩展成如下:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNCCCCCCCC
得到上面的字符串后,我想统计逗号、C、L、N的个数。
有人可以帮我解决这个问题吗?
您可以使用 Pattern Splitter 来完成此操作。这是取自 Dwain Camp 的 article。使用的函数 PatternSplitCM
由 Chris Morris 创建。
CREATE FUNCTION [dbo].[PatternSplitCM]
(
@List VARCHAR(8000) = NULL
,@Pattern VARCHAR(50)
) RETURNS TABLE WITH SCHEMABINDING
AS
RETURN
WITH numbers AS (
SELECT TOP(ISNULL(DATALENGTH(@List), 0))
n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d (n),
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n))
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY MIN(n)),
Item = SUBSTRING(@List,MIN(n),1+MAX(n)-MIN(n)),
[Matched]
FROM (
SELECT n, y.[Matched], Grouper = n - ROW_NUMBER() OVER(ORDER BY y.[Matched],n)
FROM numbers
CROSS APPLY (
SELECT [Matched] = CASE WHEN SUBSTRING(@List,n,1) LIKE @Pattern THEN 1 ELSE 0 END
) y
) d
GROUP BY [Matched], Grouper
使用上面的函数,您可能希望使用 '[^0-9]'
模式拆分字符串,这意味着不是数字。然后您将旋转结果,以便相应的 number
和 character
位于同一行。之后,您使用 REPLICATE
生成字符串并在最后连接它们。
您的最终查询是:
DECLARE
@String VARCHAR(8000),
@Pattern VARCHAR(50),
@Result VARCHAR(MAX)
SELECT
@String = '32,21C2L5N8C',
@Pattern = '[^0-9]',
@Result = ''
;WITH Cte AS(
SELECT
ID = (s.ItemNumber + 1)/ 2,
Number = MAX(CASE WHEN s.ItemNumber % 2 = 1 THEN s.Item END),
Character = MAX(CASE WHEN s.ItemNumber % 2 = 0 THEN s.Item END)
FROM dbo.[PatternSplitCM](@String, @Pattern) s
GROUP BY (s.ItemNumber + 1)/ 2
)
SELECT @Result = @Result + REPLICATE(Character, Number) FROM Cte ORDER BY ID
SELECT @Result
这里是一步一步的解释:
首先,使用模式 '[^0-9]'
.
拆分给定的字符串
SELECT * FROM dbo.[PatternSplitCM](@String, @Pattern) s
结果是:
ItemNumber Item Matched
-------------------- ---------- -----------
1 32 0
2 , 1
3 21 0
4 C 1
5 2 0
6 L 1
7 5 0
8 N 1
9 8 0
10 C 1
其次,旋转结果,使相应的数字和字符位于同一行:
SELECT
ID = (s.ItemNumber + 1)/ 2,
Number = MAX(CASE WHEN s.ItemNumber % 2 = 1 THEN s.Item END),
Character = MAX(CASE WHEN s.ItemNumber % 2 = 0 THEN s.Item END)
FROM dbo.[PatternSplitCM](@String, @Pattern) s
GROUP BY (s.ItemNumber + 1)/ 2
结果是:
ID Number Character
------ ---------- ----------
1 32 ,
2 21 C
3 2 L
4 5 N
5 8 C
最后,使用REPLICATE(Number, Character)
生成每一个字符串并拼接得到最终结果:
SELECT @Result = @Result + REPLICATE(Character, Number) FROM Cte ORDER BY ID
SELECT @Result
结果是:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNCCCCCCCC
您可以提取 数字 和 none 数字字符 然后复制每个字符,在 SQL服务器你可以使用patindex and replicate函数(解释在代码中):
--table variable for holding extracted numbers and none number characters
declare @t table(id int identity(1,1), num int, nonnum char(1))
declare @str1 varchar(50)='32,21C2L5N8C' -- your current given string
declare @int1 varchar(50)='' --for number
declare @str2 varchar(50)='' --for none numeric characters
declare @result varchar(max)=''
while len(@str1)>1 --for parsing the given string
begin
while (Select PatIndex('%[0-9]%', @str1))=1 --extract number
begin
set @int1=@int1+substring(@str1,1,1)
set @str1=substring(@str1,2,len(@str1)-1)
end
set @str2=substring(@str1,1,1) --extract none numeric character
set @str1=substring(@str1,2,len(@str1)-1)
insert into @t(num,nonnum)values (@int1,@str2)
set @int1=''
set @str2=''
end
select @result=@result+replicate(nonnum,num) from @t
select @result
输出:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNCCCCCCCC
编辑 1: 如果在给定字符串中有前面没有数字的字符,并且您想打印它,您可以添加一个额外的 while
在上面的代码中循环:
--table variable for holding extracted numbers and none number characters
declare @t table(id int identity(1,1), num int, nonnum char(1))
declare @str1 varchar(50)='32,21C2L5NC' -- your current given string
declare @int1 varchar(50)='' --for number
declare @str2 varchar(50)='' --for none numeric characters
declare @result varchar(max)=''
while len(@str1)>1 --for parsing the given string
begin
while (Select PatIndex('%[0-9]%', @str1))=1 --extract number
begin
set @int1=@int1+substring(@str1,1,1)
set @str1=substring(@str1,2,len(@str1)-1)
end
set @str2=substring(@str1,1,1) --extract none numeric character
set @str1=substring(@str1,2,len(@str1)-1)
insert into @t(num,nonnum)values (@int1,@str2)
set @int1=''
set @str2=''
while (isnumeric(substring(@str1,1,1))=0 and len(@str1)>=1)
begin
set @str2=substring(@str1,1,1) --extract none numeric character
set @str1=substring(@str1,2,len(@str1)-1)
insert into @t(num,nonnum)values (1,@str2)
set @int1=''
set @str2=''
end
end
select @result=@result+replicate(nonnum,num) from @t
select @result
输出:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNC
编辑2:如果你想要每个字符的重复次数,只需查询上面代码中的@t
table变量,我的意思是上面查询的结尾说:
select nonnum [char],num [repeat] from @t
输出:
char repeat
, 32
C 21
L 2
N 5
C 1
我有一个字符串,例如 32,21C2L5N8C
存储在一个字段中。现在我想把这个字符串扩展成如下:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNCCCCCCCC
得到上面的字符串后,我想统计逗号、C、L、N的个数。
有人可以帮我解决这个问题吗?
您可以使用 Pattern Splitter 来完成此操作。这是取自 Dwain Camp 的 article。使用的函数 PatternSplitCM
由 Chris Morris 创建。
CREATE FUNCTION [dbo].[PatternSplitCM]
(
@List VARCHAR(8000) = NULL
,@Pattern VARCHAR(50)
) RETURNS TABLE WITH SCHEMABINDING
AS
RETURN
WITH numbers AS (
SELECT TOP(ISNULL(DATALENGTH(@List), 0))
n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d (n),
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
(VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n))
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY MIN(n)),
Item = SUBSTRING(@List,MIN(n),1+MAX(n)-MIN(n)),
[Matched]
FROM (
SELECT n, y.[Matched], Grouper = n - ROW_NUMBER() OVER(ORDER BY y.[Matched],n)
FROM numbers
CROSS APPLY (
SELECT [Matched] = CASE WHEN SUBSTRING(@List,n,1) LIKE @Pattern THEN 1 ELSE 0 END
) y
) d
GROUP BY [Matched], Grouper
使用上面的函数,您可能希望使用 '[^0-9]'
模式拆分字符串,这意味着不是数字。然后您将旋转结果,以便相应的 number
和 character
位于同一行。之后,您使用 REPLICATE
生成字符串并在最后连接它们。
您的最终查询是:
DECLARE
@String VARCHAR(8000),
@Pattern VARCHAR(50),
@Result VARCHAR(MAX)
SELECT
@String = '32,21C2L5N8C',
@Pattern = '[^0-9]',
@Result = ''
;WITH Cte AS(
SELECT
ID = (s.ItemNumber + 1)/ 2,
Number = MAX(CASE WHEN s.ItemNumber % 2 = 1 THEN s.Item END),
Character = MAX(CASE WHEN s.ItemNumber % 2 = 0 THEN s.Item END)
FROM dbo.[PatternSplitCM](@String, @Pattern) s
GROUP BY (s.ItemNumber + 1)/ 2
)
SELECT @Result = @Result + REPLICATE(Character, Number) FROM Cte ORDER BY ID
SELECT @Result
这里是一步一步的解释:
首先,使用模式 '[^0-9]'
.
SELECT * FROM dbo.[PatternSplitCM](@String, @Pattern) s
结果是:
ItemNumber Item Matched
-------------------- ---------- -----------
1 32 0
2 , 1
3 21 0
4 C 1
5 2 0
6 L 1
7 5 0
8 N 1
9 8 0
10 C 1
其次,旋转结果,使相应的数字和字符位于同一行:
SELECT
ID = (s.ItemNumber + 1)/ 2,
Number = MAX(CASE WHEN s.ItemNumber % 2 = 1 THEN s.Item END),
Character = MAX(CASE WHEN s.ItemNumber % 2 = 0 THEN s.Item END)
FROM dbo.[PatternSplitCM](@String, @Pattern) s
GROUP BY (s.ItemNumber + 1)/ 2
结果是:
ID Number Character
------ ---------- ----------
1 32 ,
2 21 C
3 2 L
4 5 N
5 8 C
最后,使用REPLICATE(Number, Character)
生成每一个字符串并拼接得到最终结果:
SELECT @Result = @Result + REPLICATE(Character, Number) FROM Cte ORDER BY ID
SELECT @Result
结果是:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNCCCCCCCC
您可以提取 数字 和 none 数字字符 然后复制每个字符,在 SQL服务器你可以使用patindex and replicate函数(解释在代码中):
--table variable for holding extracted numbers and none number characters
declare @t table(id int identity(1,1), num int, nonnum char(1))
declare @str1 varchar(50)='32,21C2L5N8C' -- your current given string
declare @int1 varchar(50)='' --for number
declare @str2 varchar(50)='' --for none numeric characters
declare @result varchar(max)=''
while len(@str1)>1 --for parsing the given string
begin
while (Select PatIndex('%[0-9]%', @str1))=1 --extract number
begin
set @int1=@int1+substring(@str1,1,1)
set @str1=substring(@str1,2,len(@str1)-1)
end
set @str2=substring(@str1,1,1) --extract none numeric character
set @str1=substring(@str1,2,len(@str1)-1)
insert into @t(num,nonnum)values (@int1,@str2)
set @int1=''
set @str2=''
end
select @result=@result+replicate(nonnum,num) from @t
select @result
输出:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNCCCCCCCC
编辑 1: 如果在给定字符串中有前面没有数字的字符,并且您想打印它,您可以添加一个额外的 while
在上面的代码中循环:
--table variable for holding extracted numbers and none number characters
declare @t table(id int identity(1,1), num int, nonnum char(1))
declare @str1 varchar(50)='32,21C2L5NC' -- your current given string
declare @int1 varchar(50)='' --for number
declare @str2 varchar(50)='' --for none numeric characters
declare @result varchar(max)=''
while len(@str1)>1 --for parsing the given string
begin
while (Select PatIndex('%[0-9]%', @str1))=1 --extract number
begin
set @int1=@int1+substring(@str1,1,1)
set @str1=substring(@str1,2,len(@str1)-1)
end
set @str2=substring(@str1,1,1) --extract none numeric character
set @str1=substring(@str1,2,len(@str1)-1)
insert into @t(num,nonnum)values (@int1,@str2)
set @int1=''
set @str2=''
while (isnumeric(substring(@str1,1,1))=0 and len(@str1)>=1)
begin
set @str2=substring(@str1,1,1) --extract none numeric character
set @str1=substring(@str1,2,len(@str1)-1)
insert into @t(num,nonnum)values (1,@str2)
set @int1=''
set @str2=''
end
end
select @result=@result+replicate(nonnum,num) from @t
select @result
输出:
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,CCCCCCCCCCCCCCCCCCCCCLLNNNNNC
编辑2:如果你想要每个字符的重复次数,只需查询上面代码中的@t
table变量,我的意思是上面查询的结尾说:
select nonnum [char],num [repeat] from @t
输出:
char repeat
, 32
C 21
L 2
N 5
C 1