Reputation: 953
I have a string like this:
Apple
I want to include a separator after each character so the end result will turn out like this:
A,p,p,l,e
In C#, we have one liner method to achieve the above with Regex.Replace('Apple', ".{1}", "$0,");
I can only think of looping each character with charindex
to append the separator but seems a little complicated. Is there any elegant way and simpler way to achieve this?
Upvotes: 1
Views: 3448
Reputation: 7918
If you have SQL Server 2017 and a copy of ngrams8k it's ultra simple:
declare @word varchar(100) = 'apple';
select newString = string_agg(token, ',') within group (order by position)
from dbo.ngrams8k(@word,1);
For pre-2017 systems it's almost as simple:
declare @word varchar(100) = 'apple';
select newstring =
( select token + case len(@word)+1-position when 1 then '' else ',' end
from dbo.ngrams8k(@word,1)
order by position
for xml path(''))
Upvotes: 1
Reputation: 6612
In following SQL scripts, I get each character using SUBSTRING() function using with a number table (basically I used spt_values view here for simplicity) and then I concatenate them via two different methods, you can choose one
If you are using SQL Server 2017, we have a new SQL string aggregation function First script uses string_agg function
declare @str nvarchar(max) = 'Apple'
SELECT
string_agg( substring(@str,number,1) , ',') Within Group (Order By number)
FROM master..spt_values n
WHERE
Type = 'P' and
Number between 1 and len(@str)
If you are working with a previous version, you can use string concatenation using FOR XML Path and SQL Stuff function as follows
declare @str nvarchar(max) = 'Apple'
; with cte as (
SELECT
number,
substring(@str,number,1) as L
FROM master..spt_values n
WHERE
Type = 'P' and
Number between 1 and len(@str)
)
SELECT
STUFF(
(
SELECT
',' + L
FROM cte
order by number
FOR XML PATH('')
), 1, 1, ''
)
Both solution yields the same result, I hope it helps
Upvotes: 1
Reputation: 8033
Try this
declare @var varchar(50) ='Apple'
;WITH CTE
AS
(
SELECT
SeqNo = 1,
MyStr = @var,
OpStr = CAST('' AS VARCHAR(50))
UNION ALL
SELECT
SeqNo = SeqNo+1,
MyStr = MyStR,
OpStr = CAST(ISNULL(OpStr,'')+SUBSTRING(MyStR,SeqNo,1)+',' AS VARCHAR(50))
FROM CTE
WHERE SeqNo <= LEN(@var)
)
SELECT
OpStr = LEFT(OpStr,LEN(OpStr)-1)
FROM CTE
WHERE SeqNo = LEN(@Var)+1
Upvotes: 0
Reputation: 953
Thanks HABO for the suggestions. I'm able to generate the result that I want using the code but takes a little bit of time to really understand how the code work.
After some searching, I manage to found one useful article to insert empty spaces between each character and it's easier for me to understand.
I modify the code a little to define and include desire separator instead of fixing it to space as the separator:
DECLARE @pos INT = 2 -- location where we want first space
DECLARE @result VARCHAR(100) = 'Apple'
DECLARE @separator nvarchar(5) = ','
WHILE @pos < LEN(@result)+1
BEGIN
SET @result = STUFF(@result, @pos, 0, @separator);
SET @pos = @pos+2;
END
select @result; -- Output: A,p,p,l,e
Upvotes: 2
Reputation: 15816
One ugly way to do it is to split the string into characters, ideally using a numbers table, and reassemble it with the desired separator.
A less efficient implementation uses recursion in a CTE to split the characters and insert the separator between pairs of characters as it goes:
declare @Sample as VarChar(20) = 'Apple';
declare @Separator as Char = ',';
with Characters as (
select 1 as Position, Substring( @Sample, 1, 1 ) as Character
union all
select Position + 1,
case when Position & 1 = 1 then @Separator else Substring( @Sample, Position / 2 + 1, 1 ) end
from Characters
where Position < 2 * Len( @Sample ) - 1 )
select Stuff( ( select Character + '' from Characters order by Position for XML Path( '' ) ), 1, 0, '' ) as Result;
You can replace the select Stuff...
line with select * from Characters;
to see what's going on.
Upvotes: 0