Split string into letters separated by a full stop (SQL) - sql

I am trying to write a stored procedure which accepts a string parameter and returns it with each character separated by a full stop.
So for example I want the SP to accept parameter DOG and return D.O.G.
I have tried to use the STRING_SPLIT function as follows:
select STRING_SPLIT(#myString, '')
but it doesn't seem to be compatible with the version of SQL I'm using (2014) (the error message says it is not a recognised function). Even if it did work I'm not sure how to then insert full stops.
It seems like there should be an easy way to do this but I just can't find it!
Please let me know if you need any further information.
Many thanks.

Misread the question at first. This answer uses NGRams8K to split the parameter into characters, and then FOR XML PATH to join it back up:
SELECT (SELECT token +'.'
FROM dbo.NGrams8k('DOG',1)
ORDER BY position
FOR XML PATH(''))

If I understood well this is the best approach I can think of right now, using the answer from this question T-SQL Split Word into characters
with cte as (
select
substring(a.b, v.number+1, 1) as col
,rn = ROW_NUMBER() over (order by (select 0))
from (select 'DOG' b) a
join master..spt_values v
on v.number < len(a.b)
where v.type = 'P'
)
select distinct
STUFF((SELECT '.' + col FROM cte order by rn FOR XML PATH('')),1,1,'') as col
from cte

There is no built-in function to accomplish what you are after, but you can easily do it using a simple while loop.
Iterate through each character in the string and use CONCAT:
DECLARE #InputString NVARCHAR(200);
DECLARE #Seperator CHAR(1);
DECLARE #OutputString NVARCHAR(MAX);
DECLARE #Counter INT;
SET #InputString = N'TestString';
SET #Seperator = '.';
SET #Counter = 1;
WHILE #Counter <= LEN(#InputString)
BEGIN
SET #OutputString = CONCAT(
#OutputString
, SUBSTRING(#InputString, #Counter, 1)
, #Seperator
);
SET #Counter = #Counter + 1;
END;
SELECT #OutputString;

You can use a simple while loop with stuff:
declare #s varchar(max) ='dog'
declare #counter int = 0
declare #len int = len(#s)
while #counter < #len - 1
begin
set #s = stuff(#s, #len - #counter, 0, '.')
set #counter = #counter + 1
end
select #s + '.' as result
Since your input is a short string performances should not be a great concern: I tested this solution with a 8000 char string and the result was returned instantly.
Result:

Related

How to replace string in SQL from index to index

Hi guys can someone help me to write this?
DECLARE #STR VARCHAR(55) = 'Name';
SELECT // SOME LOGIC
RESULT => 'NXXE'
I would like this logic to be generalized to replace every string except the first and last character.
if dynamic data masking is not an answer you can use query below :
DECLARE #str VARCHAR(100) = 'yourstring'
SELECT UPPER(LEFT(#str,1) + REPLICATE('x',LEN(#str) -2)+ RIGHT(#str,1))
This is what you want
DECLARE #STR VARCHAR(55) = 'Name';
declare #i int
Set #i = 0
while #i <= len(#STR )
begin
select #i = #i + 1
if(#i>1 AND #i<len(#STR ))
select #STR = STUFF(#STR , #i, 1, 'X')
END
SELECT #STR

Variable in query doesn't work

I'm facing some problem with a SQL query, I'm creating a variable :
declare #material varchar(500)
declare #typ varchar(200)
declare #strsql varchar(max)
set #typ = 'papier'
select #material = (SELECT + rtrim(ltrim([grupa])) + ','
FROM [test].[dbo].[GT]
WHERE (typ = #typ) FOR XML PATH(''))
set #material = left(#material, len(#material)-1)
set #material = replace(#material, ',' ,''',''')
set #material = '''' + #material + ''''
select #material
The output from variable is :
'test','test2'
And here is a little part of my main code :
SELECT
Number,
isnull(sum((case
when [Group] in ('test','test2')
then isnull(cast([Quantity] as int), 0)
end)), 0) as other
FROM
[dbo].[test-table]
which works correct but when I'm trying to do this like that :
SELECT
Number,
isnull(sum((case
when [Group] in (#material)
then isnull(cast([Quantity] as int), 0)
end)), 0) as other
FROM
[dbo].[test-table]
Output is wrong (different). Can anyone tell me why? It's kinda this same.
It's kind of the same, but it's not the same. What you are looking to get is: in ('test','test2'), what you get is: in (''test','test2'').
You will have to build the rest of your query dynamically, something like:
DECLARE #SQL NVARCHAR(MAX) = 'SELECT
Number
,isnull(sum((case when [Group] in ('+ #material + ')
then isnull(cast([Quantity] as int),0) end)),0) as other
from [dbo].[test-table]'
EXEC sys.sp_executesql #SQL
If you say the output is wrong, it's best to show the actual output and why it is wrong. Saying "Output is different comparing to first query - it should be the same" is not enough, in most cases.
edit:
If you don't want to use dynamic sql (which makes sense), you could do something like this (which is actually much more readable than dynamic):
SELECT Number
, ISNULL(SUM(data),0) as other
FROM (
SELECT Number
, CASE WHEN [Group] IN (SELECT grupa FROM [dbo].[GT] WHERE typ = #typ)
THEN ISNULL(CAST([Quantity] AS INT), 0)
END data
FROM [dbo].[test-table]
) TT
GROUP BY Number
I am making a lot of assumptions about your goal, your schema and your data here though. Without more info, this is probably the best I can do...(There may be some performance tweaking to be done, but this is the essence)
Try to use a function for split the string:
CREATE FUNCTION [dbo].[FN_SplitString](#String nvarchar(4000), #Delimiter char(1))
RETURNS #Results TABLE (Items nvarchar(4000))
AS
BEGIN
IF #String IS NULL RETURN
IF LTRIM(RTRIM(#String)) = '' RETURN
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
SELECT #INDEX = 1
WHILE #INDEX !=0
BEGIN
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
IF #INDEX !=0
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
ELSE
SELECT #SLICE = #STRING
INSERT INTO #Results(Items) VALUES(#SLICE)
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
IF LEN(#STRING) = 0 BREAK
END
RETURN
Then use it in this way:
SELECT
Number
,isnull(sum((case when [Group] in (SELECT Items, FROM FN_SplitString(#material,','))
then isnull(cast([Quantity] as int),0) end)),0) as other
from [dbo].[test-table]
In SQL Server, if you pass a comma separated list as a variable in IN Clause in T-SQL, it would not give error but you will not even get expected result either.
There are two solutions to handle this:
Using Dynamic query
Using Split function

UDF to insert a text string in to each row of a table

I've been searching high and low for an answer and I can't seem to find anything that points me in the right direction.
I need to create a UDF that will extract each word of a text string and return a table with each word of the string in a separate row.
The UDF is only able to take in one variable '#mytext'.
We can assume that the text string is separated by a single space and may contain commas or periods.
For example, "don’t worry about failures, worry about the chances you miss when you don’t even try." would need to return a table with each word on a separate row of a column without the commas or periods present.
I'm figuring that the text string would need to be separated with a common value that could be used to separate each word for insert, but I could totally be wrong.
Any help with this would be really appreciated!
Based on what I've said so far, here is my far from complete code that I'm not too sure how to proceed with
create function [dbo].[textConverter]
(
#mytext nvarchar(max)
)
returns #text_string table
(
word nvarchar
)
as
begin
set #mytext = replace(#mytext, 'what needs to be changed', 'what it needs to be changed too')
--insert string to table
end
EDIT
I've checked out a couple of links and uncovered a little more information on this, I've now got this code. However it exits with an error. The example that was used in the article I found the code on used numbers in the insert so maybe this is the issue??
create function [dbo].[textConverter]
(
#mytext varchar(max)
)
returns #text_string table
(
word nvarchar
)
as
begin
--Change string to be seperated by commas
set #mytext = replace(#mytext, ' ', ',')
set #mytext = replace(#mytext, '.',',')
--Eliminate double commas
set #mytext = replace(#mytext, ',,', ',')
declare #name nvarchar(255)
declare #pos int
while CHARINDEX(',', #mytext) > 0
begin
select #pos = CHARINDEX(',', #mytext)
select #name = SUBSTRING(#mytext, 1, #pos-1)
insert into #text_string
select #name
select #mytext = SUBSTRING(#mytext, #pos+1, LEN(#mytext)-#pos)
end
insert into #text_string
select #mytext
return
end
--To use function
select * from dbo.textConverter('don’t worry about failures, worry about the chances you miss when you don’t even try.')
See the answer below, It is not in complete shape, but can be developed into a user defined function.
Declare #Sentence Varchar(max) = 'don’t worry about failures, worry about the chances you miss when you don’t even try.'
Set #Sentence = Replace(Replace(Replace(Replace(#Sentence,',',' '),'.',' '),' ',' '),' ',' ')
Declare #e int = (Select Len(#Sentence) - Len(Replace(#Sentence,' ','')))
Declare #s int = 1
Declare #Result Table(id int identity(1,1),Words varchar(max))
--Select #s,#e
While #s <= #e
begin
Insert into #Result
Select Left(#Sentence,Charindex(' ',#Sentence,1)-1)
Set #Sentence = Substring(#Sentence,Charindex(' ',#Sentence,1) + 1,Len(#Sentence) )
Set #s = #s + 1
End
Insert into #Result
Select #Sentence
Select * from #Result
Result
----+-----------
id |Words
----+-----------
1 |don’t
2 |worry
3 |about
4 |failures
5 |worry
6 |about
7 |the
8 |chances
9 |you
10 |miss
11 |when
12 |you
13 |don’t
14 |even
15 |try
----+-----------
I adapted some of the code from http://sqlperformance.com/2012/07/t-sql-queries/split-strings as my situation meant that the delimiter couldn't specified as input. I could only use on input and that was the text string. As such, the following worked for me:
create function [dbo].[textConverter]
(
#string nvarchar(max)
)
returns #output table(splitdata nvarchar(max)
)
begin
--Change string to be seperated by commas
set #string = replace(#string, ' ', ',')
set #string = replace(#string, '.',',')
--Eliminate double commas
set #string = replace(#string, ',,', ',')
declare #start int, #end int
select #start = 1, #end = charindex(',',#string)
while #start < len(#string) + 1
begin
if #end = 0
set #end = len(#string) + 1
insert into #output (splitdata)
values(substring(#string, #start, #end - #start))
set #start = #end + 1
set #end = charindex(',', #string, #start)
end
return
end

Append a specific character after each character of a string in sql server

Thanks to advise me for the below issue:
I am using below query to fetch the value of a column:
Select OptionList = case when isnull(AS_CIS_Code,'') <> '' then AS_CIS_Code
else ''
end
from added_services
AS_CIS_Code column is of varchar(10) in added_services table. It contains values like 'AB', 'ABC', 'GHKIK', 'UYTIOPJ' and so on which represents different codes.
Now I have to select these codes after modifying the above query so that '_' is appended after each character.
Like it should be fetched as 'A_B_', 'A_B_C_', 'G_H_K_I_K_', 'U_Y_T_I_O_P_J_'.
How should I implement it? Using a temp table will down the performance for one column only, so should I use while loop or please suggest me better alternatives.
Try this:
DECLARE #Input VARCHAR(100) = 'TESTING'
DECLARE #Pos INT = LEN(#Input)
WHILE #Pos > 1
BEGIN
SET #Input = STUFF(#Input,#Pos,0,'_')
SET #Pos = #Pos - 1
END
SELECT #Input
Output
T_E_S_T_I_N_G
UDF
CREATE FUNCTION PadStr(#Data VARCHAR(100)) RETURNS VARCHAR(200)
AS
BEGIN
DECLARE #Input VARCHAR(200) = #Data
DECLARE #Pos INT = LEN(#Input)
WHILE #Pos > 1
BEGIN
SET #Input = STUFF(#Input,#Pos,0,'_')
SET #Pos = #Pos - 1
END
RETURN #Input + '_'
END
Output
SELECT dbo.PadStr('TESTING') -- T_E_S_T_I_N_G_
You can split the string using a numbers table and the rebuild it using for xml path().
select isnull(C.Value, '') as AS_CIS_Code
from added_services as A
cross apply (
select substring(A.AS_CIS_Code, T.N, 1)+'_'
from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) as T(N)
where T.N <= len(A.AS_CIS_Code)
order by T.N
for xml path('')
) as C(Value)
SQL Fiddle
Try this
Create Function Code_Pad
(
#code varchar(max)
)
returns varchar(max)
as
begin
Declare #coding varchar(max) =''
Declare #i int = 1
WHILE(LEN(#Coding)<=2*len(#code)-1)
begin
Select #coding = #coding+SUBSTRING(#code,#i,1)+'_'
set #i=#i+1
end
return #coding
end
End of Function
Select OptionList = case when isnull(AS_CIS_Code,'') <> '' then dbo.Code_Pad(AS_CIS_Code) else ''
end
from added_services
May not be best solution, but works in one query using recursion
;WITH valCTE(Replaced,ToBeReplaced,Position)
AS
(
SELECT CAST(LEFT(AS_CIS_Code,1) + '_' AS VARCHAR(20))
,SUBSTRING(AS_CIS_Code,2,LEN(AS_CIS_Code)-1)
,1
FROM added_services
UNION ALL
SELECT CAST(Replaced + LEFT(ToBeReplaced,1) + '_' AS VARCHAR(20))
,SUBSTRING(ToBeReplaced,2,LEN(ToBeReplaced)-1)
,Position+1
FROM valCTE
WHERE LEN(ToBeReplaced)>0
)
SELECT TOP 1 LEFT(Replaced,LEN(Replaced)-1) -- remove last _
FROM valCTE
ORDER BY Position DESC

How to change case in string

My table has one column that contain strings like: ” HRM_APPLICATION_DELAY_IN”
I want to perform bellow operations on each row on this column
convert to lower case
remove underscore “_”
change case (convert to upper case) of the character after the underscore like: ” hrm_Application_Delay_In”
Need help for conversion. Thanks for advance
Here is a function to achieve it:
create function f_test
(
#a varchar(max)
)
returns varchar(max)
as
begin
set #a = lower(#a)
while #a LIKE '%\_%' ESCAPE '\'
begin
select #a = stuff(#a, v, 2, upper(substring(#a, v+1,1)))
from (select charindex('_', #a) v) a
end
return #a
end
Example:
select dbo.f_test( HRM_APPLICATION_DELAY_IN')
Result:
hrmApplicationDelayIn
To update your table here is an example how to write the syntax with the function:
UPDATE <yourtable>
SET <yourcolumn> = dbo.f_test(col)
WHERE <yourcolumn> LIKE '%\_%' ESCAPE '\'
For a variable this is overkill, but I'm using this to demonstrate a pattern
declare #str varchar(100) = 'HRM_APPLICATION_DELAY_IN';
;with c(one,last,rest) as (
select cast(lower(left(#str,1)) as varchar(max)),
left(#str,1), stuff(lower(#str),1,1,'')
union all
select one+case when last='_'
then upper(left(rest,1))
else left(rest,1) end,
left(rest,1), stuff(rest,1,1,'')
from c
where rest > ''
)
select max(one)
from c;
That can be extended to a column in a table
-- Sample table
declare #tbl table (
id int identity not null primary key clustered,
str varchar(100)
);
insert #tbl values
('HRM_APPLICATION_DELAY_IN'),
('HRM_APPLICATION_DELAY_OUT'),
('_HRM_APPLICATION_DELAY_OUT'),
(''),
(null),
('abc<de_fg>hi');
-- the query
;with c(id,one,last,rest) as (
select id,cast(lower(left(str,1)) as varchar(max)),
left(str,1), stuff(lower(str),1,1,'')
from #tbl
union all
select id,one+case when last='_'
then upper(left(rest,1))
else left(rest,1) end,
left(rest,1), stuff(rest,1,1,'')
from c
where rest > ''
)
select id,max(one)
from c
group by id
option (maxrecursion 0);
-- result
ID COLUMN_1
1 hrm_Application_Delay_In
2 hrm_Application_Delay_Out
3 _Hrm_Application_Delay_Out
4
5 (null)
6 abc<de_Fg>hi
select
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(replace(
replace(replace(replace(replace(replace(replace(lower('HRM_APPLICATION_DELAY_IN'),'_a','A'),'_b','B'),'_c','C'),'_d','D'),'_e','E'),'_f','F'),
'_g','G'),'_h','H'),'_i','I'),'_j','J'),'_k','K'),'_l','L'),
'_m','M'),'_n','N'),'_o','O'),'_p','P'),'_q','Q'),'_r','R'),
'_s','S'),'_t','T'),'_u','U'),'_v','V'),'_w','W'),'_x','X'),
'_y','Y'),'_z','Z'),'_','')
Bellow two steps can solve problem,as example i use sys.table.user can use any one
declare #Ret varchar(8000), #RetVal varchar(8000), #i int, #count int = 1;
declare #c varchar(10), #Text varchar(8000), #PrevCase varchar, #ModPrefix varchar(10);
DECLARE #FileDataTable TABLE(TableName varchar(200))
INSERT INTO #FileDataTable
select name FROM sys.tables where object_name(object_id) not like 'sys%' order by name
SET #ModPrefix = 'Pur'
DECLARE crsTablesTruncIns CURSOR
FOR select TableName FROM #FileDataTable
OPEN crsTablesTruncIns
FETCH NEXT FROM crsTablesTruncIns INTO #Text
WHILE ##FETCH_STATUS = 0
BEGIN
SET #RetVal = '';
select #i=1, #Ret = '';
while (#i <= len(#Text))
begin
SET #c = substring(#Text,#i,1)
--SET #Ret = #Ret + case when #Reset=1 then UPPER(#c) else LOWER(#c)
IF(#PrevCase = '_' OR #i = 1)
SET #Ret = UPPER(#c)
ELSE
SET #Ret = LOWER(#c)
--#Reset = case when #c like '[a-zA-Z]' then 0 else 1 end,
if(#c like '[a-zA-Z]')
SET #RetVal = #RetVal + #Ret
if(#c = '_')
SET #PrevCase = '_'
else
SET #PrevCase = ''
SET #i = #i +1
end
SET #RetVal = #ModPrefix + #RetVal
print cast(#count as varchar) + ' ' + #RetVal
SET #count = #count + 1
EXEC sp_RENAME #Text , #RetVal
SET #RetVal = ''
FETCH NEXT FROM crsTablesTruncIns INTO #Text
END
CLOSE crsTablesTruncIns
DEALLOCATE crsTablesTruncIns
I'd like to show you my nice and simple solution. It uses Tally function to split the string by pattern, in our case by underscope. For understanding Tally functions, read this article.
So, this is how my tally function looks like:
CREATE FUNCTION [dbo].[tvf_xt_tally_split](
#String NVARCHAR(max)
,#Delim CHAR(1))
RETURNS TABLE
as
return
(
WITH Tally AS (SELECT top (select isnull(LEN(#String),100)) n = ROW_NUMBER() OVER(ORDER BY [name]) from master.dbo.syscolumns)
(
SELECT LTRIM(RTRIM(SUBSTRING(#Delim + #String + #Delim,N+1,CHARINDEX(#Delim,#Delim + #String + #Delim,N+1)-N-1))) Value, N as Ix
FROM Tally
WHERE N < LEN(#Delim + #String + #Delim)
AND SUBSTRING(#Delim + #String + #Delim,N,1) = #Delim
)
)
This function returns a table, where each row represents part of string between #Delim (in our case between underscopes). Rest of the work is simple, just cobination of LEFT, RIGHT, LEN, UPPER and LOWER functions.
declare #string varchar(max)
set #string = ' HRM_APPLICATION_DELAY_IN'
-- convert to lower case
set #string = LOWER(#string)
declare #output varchar(max)
-- build string
select #output = coalesce(#output + '_','') +
UPPER(left(Value,1)) + RIGHT(Value, LEN(Value) - 1)
from dbo.tvf_xt_tally_split(#string, '_')
-- lower first char
select left(lower(#output),1) + RIGHT(#output, LEN(#output) - 1)