How to compare two string elements in SQL Server - sql-server

I have two strings in SQL Server.
For example:
declare #str1 as varchar(max)
declare #str2 as varchar(max)
set #str1 ='10:00am,2:00pm'
set #str2 = '10:00am,12:00pm,2:00pm,4:00pm,6:00pm,8:00pm'
and I want to compare the two strings and want to get those elements string from #str2 which are not in #str1.
That means the result should be :
#str3 = '12:00pm,4:00pm,6:00pm,8:00pm'

Try this :-
declare #str1 as varchar(max)
declare #str2 as varchar(max)
set #str1 ='10:00am,2:00pm'
set #str2 = '10:00am,12:00pm,2:00pm,4:00pm,6:00pm,8:00pm'
--the below 2 CTE's are used for splitting the string into different rows
;with cteStr1(str1) as
(
SELECT
RIGHT(LEFT(#str1,Number-1),
CHARINDEX(',',REVERSE(LEFT(','+#str1,Number-1)))) as str1
FROM
master..spt_values
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(#str1)+1
AND
(SUBSTRING(#str1,Number,1) = ',' OR SUBSTRING(#str1,Number,1) = '')
),cteStr2(str2) as
(
SELECT
RIGHT(LEFT(#str2,Number-1),
CHARINDEX(',',REVERSE(LEFT(','+#str2,Number-1)))) as str2
FROM
master..spt_values
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(#str2)+1
AND
(SUBSTRING(#str2,Number,1) = ',' OR SUBSTRING(#str2,Number,1) = '')
)
Select str2 from cteStr2
except
select str1 from cteStr1

Try this
DECLARE #str1 VARCHAR(MAX)
DECLARE #str2 VARCHAR(MAX)
SET #str1 ='10:00am,2:00pm'
SET #str2 = '10:00am,12:00pm,2:00pm,4:00pm,6:00pm,8:00pm'
SET #str1 = ',' + #str1 + ','
SET #str2 = ',' + #str2 + ','
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #str1) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #str1)
SELECT #name = SUBSTRING(#str1, 1, #pos-1)
SELECT #str1 = SUBSTRING(#str1, #pos+1, LEN(#str1)-#pos)
IF #name <> ''
BEGIN
SET #str2 = REPLACE(#str2,','+#name,'')
END
END
SET #str2 = REPLACE(#str2,','+#name,'')
SELECT SUBSTRING(#str2, 2, LEN(#str2)-2) AS Result

Try this one -
DECLARE
#str1 VARCHAR(500)
, #str2 VARCHAR(500)
SELECT
#str1 = '10:00am,2:00pm'
, #str2 = '10:00am,12:00pm,2:00pm,4:00pm,6:00pm,8:00pm'
;WITH cte AS
(
SELECT
id = p.value('(./n)[1]', 'INT')
, tm = p.value('(./s)[1]', 'VARCHAR(500)')
FROM (
SELECT field = CAST('<r><s>' + REPLACE(SUBSTRING(t.string + ',', 1, LEN(t.string + ',')), ',', '</s><n>' + CAST(t.id AS VARCHAR(10)) + '</n></r><r><s>') + '</s></r>' AS XML)
FROM (
SELECT string = #str1, id = 1
UNION ALL
SELECT #str2, 2
) t
) d
CROSS APPLY field.nodes('/r') t(p)
WHERE t.p.exist('n') = 1
)
SELECT tm FROM cte WHERE id = 2
EXCEPT
SELECT tm FROM cte WHERE id = 1
Or try this -
;WITH cte2 AS
(
SELECT
t.id
, tm =
SUBSTRING(
',' + t.string + ','
, number + 1
, CHARINDEX(',', ',' + t.string + ',', number + 1) - number - 1)
FROM (
SELECT string = #str1, id = 1
UNION ALL
SELECT #str2, 2
) t
CROSS JOIN [master].dbo.spt_values n
WHERE [type] = 'p'
AND number <= LEN(',' + t.string + ',') - 1
AND SUBSTRING(',' + t.string + ',', number, 1) = ','
)
SELECT tm FROM cte2 WHERE id = 2
EXCEPT
SELECT tm FROM cte2 WHERE id = 1

Related

Generate dynamic PATINDEX statement

I have the following two strings:
DECLARE #Str1 VARCHAR(MAX) = 'John A Mak|Street Road UAE'
DECLARE #Str2 VARCHAR(MAX) = '[First Name],[Last Name],[Middle Name]|[Address1],[Address2]'
Note: Both strings are dynamic may comes with more or less values.
Expected result: Want to if any of the given text present in the given columns using the PATINDEX. The following PATINDEX statement gonna used in the WHERE clause of the SELECT statement.
PATINDEX('John',[First Name]) + PATINDEX('A',[First Name]) + PATINDEX('Mak',[First Name]) +
PATINDEX('John',[Last Name]) + PATINDEX('A',[Last Name]) + PATINDEX('Mak',[Last Name]) +
PATINDEX('John',[Middle Name]) + PATINDEX('A',[Middle Name]) + PATINDEX('Mak',[Middle Name]) +
PATINDEX('Street',[Address1]) + PATINDEX('Road',[Address1]) + PATINDEX('UAE',[Address1]) +
PATINDEX('Street',[Address2]) + PATINDEX('Road',[Address2]) + PATINDEX('UAE',[Address2]) > 0
My try:
DECLARE #Str1 VARCHAR(MAX) = 'John A Mak|Street Road UAE'
DECLARE #Str2 VARCHAR(MAX) = '[First Name],[Last Name],[Middle Name]|[Address1],[Address2]'
DECLARE #Length int = 0
DECLARE #Length1 int = 0
DECLARE #Length2 int = 0
DECLARE #Position int = 0
DECLARE #Position1 int = 0
DECLARE #Position2 int = 0
DECLARE #Value varchar(max)
DECLARE #Value1 varchar(max)
DECLARE #Value2 varchar(max)
DECLARE #P_Str2 VARCHAR(MAX) = ''
DECLARE #P_Str3 VARCHAR(MAX) = ''
DECLARE #P_Str1 VARCHAR(MAX) = ''
DECLARE #FinalString VARCHAR(MAX) = ''
SET #P_Str1 = #Str1+'|';
SET #P_Str3 = #Str2+'|';
IF OBJECT_ID('tempdb..#tempt', 'U') IS NOT NULL DROP TABLE #tempt;
CREATE TABLE #tempt(keywords varchar(max));
WHILE CHARINDEX('|', #P_Str3, #Position2+1)>0
BEGIN
set #Length2 = CHARINDEX('|', #P_Str3, #Position2+1) - #Position2
set #Value2 = SUBSTRING(#P_Str3, #Position2, #Length2)
SET #P_Str2 = #Value2+',';
PRINT('--'+#P_Str2);
--WHILE LOOP for creating string for PAT INDEX
WHILE CHARINDEX(',', #P_Str2, #Position+1)>0
BEGIN
set #Length = CHARINDEX(',', #P_Str2, #Position+1) - #Position
set #Value = SUBSTRING(#P_Str2, #Position, #Length)
WHILE CHARINDEX('|', #P_Str1, #Position1+1)>0
BEGIN
set #Length1 = CHARINDEX('|', #P_Str1, #Position1+1) - #Position1
set #Value1 = SUBSTRING(#P_Str1, #Position1, #Length1)
PRINT('Value1--'+#Value1);
PRINT('Value--'+#Value);
INSERT INTO #tempt
SELECT DISTINCT split.a.value('.', 'VARCHAR(100)') AS Keywords
FROM
(
SELECT CAST ('<S>' + REPLACE(ltrim(rtrim(#Value1)), ' ', '</S><S>') + '</S>' AS XML) AS Element
) AS a
CROSS APPLY Element.nodes ('/S') AS split(a)
WHERE split.a.value('.', 'VARCHAR(100)') <> '';
SET #FinalString += STUFF(( SELECT '(PATINDEX('''+keywords+''','+#Value+'),''''0'''') + '
FROM #tempt FOR XML PATH('')), 1,0, '');
DELETE FROM #tempt;
SET #Position1 = CHARINDEX('|', #P_Str1, #Position1+#Length1) +1
END
SET #Position = CHARINDEX(',', #P_Str2, #Position+#Length) +1
END
SET #Position2 = CHARINDEX('|', #P_Str3, #Position2+#Length2) +1
END
PRINT(#FinalString);
But unable to get the expected result.
This is not pretty dynamic SQL, however...
USE Sandbox;
DECLARE #Str1 VARCHAR(MAX) = 'John A Mak|Street Road UAE';
DECLARE #Str2 VARCHAR(MAX) = '[First Name],[Last Name],[Middle Name]|[Address1],[Address2]';
DECLARE #WHERE nvarchar(MAX);
SET #WHERE = STUFF((SELECT N' + ' + NCHAR(10) +
STUFF((SELECT N' + ' +NCHAR(10)+
N'PATINDEX(' + QUOTENAME(DSn.Item,'''') + N',' + DSc.Item + N')' --This trusts no injection.I don't like this.
FROM dbo.DelimitedSplit8K(DS1.Item,' ') DSn
CROSS APPLY dbo.DelimitedSplit8K(DS2.Item,',') DSc
ORDER BY DSc.ItemNumber, DSn.ItemNumber
FOR XML PATH(N'')),1,4,N'')
FROM dbo.DelimitedSplit8K (#Str1,'|') DS1
CROSS APPLY dbo.DelimitedSplit8K (#Str2,'|') DS2
WHERE DS1.ItemNumber = DS2.ItemNumber
ORDER BY DS1.ItemNumber
FOR XML PATH(N'')),1,4,N'') + N' > 0'
SELECT #WHERE;
This outputs:
PATINDEX('John',[First Name]) +
PATINDEX('A',[First Name]) +
PATINDEX('Mak',[First Name]) +
PATINDEX('John',[Last Name]) +
PATINDEX('A',[Last Name]) +
PATINDEX('Mak',[Last Name]) +
PATINDEX('John',[Middle Name]) +
PATINDEX('A',[Middle Name]) +
PATINDEX('Mak',[Middle Name]) +
PATINDEX('Street',[Address1]) +
PATINDEX('Road',[Address1]) +
PATINDEX('UAE',[Address1]) +
PATINDEX('Street',[Address2]) +
PATINDEX('Road',[Address2]) +
PATINDEX('UAE',[Address2]) > 0
Note the use of DelimitedSplit8k, which you'll need on your instance to get this done.
Edit/Note: This is not injection safe. Specifically because of + DSc.Item +. The OP, in their sample data, provides already quoted strings; it is therefore assumed that the strings are properly quoted; I.e. not "[" & ColumnName & "]" (that is still open to injection, as any ] passed won't be escaped). If the columnnames are not properly quoted elsewhere, I strongly suggest removing the brackets ([]) in the passed value and using + QUOTENAME(DSc.Item) + instead.

SQL Server - string separation with length cutoff

So I have a string that is from search and it can contain multiple words I want to cutoff the words at 10 characters i.e.
DECLARE #SearchString varchar(255) = 'Administration Duplication'
becomes: 'Administra Duplicatio'
From here with few modifications:
Create Function dbo.[getFirstTenCharacters]
(
#String Varchar(Max)
)
RETURNS Varchar(Max)
BEGIN
Declare #Xml Xml
Declare #firsttenletter Varchar(Max)
Declare #delimiter Varchar(5)
SET #delimiter=' '
SET #Xml = cast(('<a>'+replace(#String,#delimiter,'</a><a>')+'</a>') AS XML)
;With CTE AS (SELECT A.value('.', 'varchar(max)') as [Column]
FROM #Xml.nodes('a') AS FN(a) )
SELECT #firsttenletter =Stuff((SELECT ' ' + LEFT([Column],10)
FROM CTE
FOR XML PATH('') ),1,0,'')
RETURN (#firsttenletter)
END
GO
SELECT dbo.[getFirstTenCharacters]('Administration Duplication');
WORKING DEMO
A rather simpler version would look something like.....
DECLARE #SearchString Varchar(255) = 'Administration Duplication'
;WITH X AS (
SELECT Split.a.value('.', 'VARCHAR(10)') Words
FROM
(SELECT Cast ('<X>' +
Replace(#SearchString, ' ', '</X><X>') + '</X>' AS XML) AS Data
) AS t CROSS APPLY Data.nodes ('/X') AS Split(a)
)
SELECT STUFF((SELECT ' ' + Words
FROM X
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'')
Create a function to split the strings.
should look something like this:
CREATE FUNCTION [dbo].[SPLIT_STRING](
#TEXT varchar(8000)
,#COLUMN int
,#SEPARATOR varchar(1)
)RETURNS varchar(8000)
AS
BEGIN
DECLARE #POS_START int = 1
DECLARE #POS_END int = CHARINDEX(#SEPARATOR, #TEXT, #POS_START)
WHILE (#COLUMN >1 AND #POS_END> 0)
BEGIN
SET #POS_START = #POS_END + 1
SET #POS_END = CHARINDEX(#SEPARATOR, #TEXT, #POS_START)
SET #COLUMN = #COLUMN - 1
END
IF #COLUMN > 1 SET #POS_START = LEN(#TEXT) + 1
IF #POS_END = 0 SET #POS_END = LEN(#TEXT) + 1
RETURN SUBSTRING (#TEXT, #POS_START, #POS_END - #POS_START)
END
THEN DO:
SELECT LEFT([dbo].[SPLIT_STRING](COLNAME,1,' '),10)+LEFT([dbo].[SPLIT_STRING](COLNAME,2,' '),10)

Split multiple string's into multiple columns

I have the following three different strings which needs to split into three different columns.
Example:
String 1:
Declare #str1 varchar(max) = 'A1,A2,A3'
String 2:
Declare #str2 varchar(max) = 'B1,B2,B3'
String 3:
Declare #str2 varchar(max) = 'C1,C2,C3'
NoteI want to store the above three strings into three different columns.
Expected Output:
colA colB colC
------------------
A1 B1 C1
A2 B2 C2
A3 B3 C3
Attempt:
SQL Fiddle: http://sqlfiddle.com/#!3/d41d8/41345
I know its a bit heavy but it will work
Declare #str1 varchar(max) = 'A1,A2,A3'
Declare #str2 varchar(max) = 'B1,B2,B3'
Declare #str3 varchar(max) = 'C1,C2,C3'
DECLARE #RowCount TINYINT
DECLARE #i TINYINT = 0
DECLARE #Table AS TABLE
(
colA varchar(MAX)
,ColB varchar(MAX)
,ColC varchar(MAX)
)
SET #RowCount = len(#str1) - len(replace(#str1, ',', ''))
WHILE(#i<=#RowCount)
BEGIN
INSERT INTO #Table
SELECT LEFT(#str1,CHARINDEX(',',#str1+',',0)-1) AS colA
,LEFT(#str2,CHARINDEX(',',#str2+',',0)-1) AS colB
,LEFT(#str3,CHARINDEX(',',#str3+',',0)-1) AS colC
SET #str1 = STUFF(#str1,1,CHARINDEX(',',#str1,0),'')
SET #str2 = STUFF(#str2,1,CHARINDEX(',',#str2,0),'')
SET #str3 = STUFF(#str3,1,CHARINDEX(',',#str3,0),'')
SET #i = #i + 1
END
SELECT * FROM #Table
If you have atmost three values then try this.
DECLARE #str1 VARCHAR(max) = 'A1,A2,A3'
SELECT Parsename(Replace(#str1, ',', '.'), 3) 'FST_COL',
Parsename(Replace(#str1, ',', '.'), 2) 'SCD_COL',
Parsename(Replace(#str1, ',', '.'), 1) 'TRD_COL' into #temp
Or
DECLARE #str1 VARCHAR(max) = 'A1,A2,A3',
#sql NVARCHAR(max),
#loop INT,
#cnt INT=1
SELECT #loop = Len(#str1) - Len(Replace(#str1, ',', '')) + 1
SET #sql=' WITH Split_cols ( xmlcol)
AS (SELECT CONVERT(XML, ''<cols><col>''
+ Replace('''
+ #str1 + ''', '','', ''</col><col>'') + ''</col></cols>'') as xmlcol)
SELECT '
WHILE #cnt <= #loop
BEGIN
SET #sql+=' xmlcol.value(''/cols[1]/col['
+ CONVERT(VARCHAR(30), #cnt)
+ ']'', ''varchar(100)'') AS col'
+ CONVERT(VARCHAR(30), #cnt) + ','
SET #cnt=#cnt + 1
END
SET #sql=LEFT(#sql, Len(#sql) - 1)
SET #sql +=' FROM Split_cols '
--PRINT #sql
EXEC Sp_executesql #sql
THIS WILL WORK WITH ANY NUMBER OF STRINGS AND VALUES NOT HARDCODED
CREATE FUNCTION dbo.splitstring (#stringToSplit VARCHAR(MAX) )
RETURNS
#returnList TABLE ([ID] INT IDENTITY(1,1),[Name] [nvarchar] (500))
AS
BEGIN
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #stringToSplit) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #stringToSplit)
SELECT #name = SUBSTRING(#stringToSplit, 1, #pos-1)
INSERT INTO #returnList
SELECT #name
SELECT #stringToSplit = SUBSTRING(#stringToSplit, #pos+1, LEN(#stringToSplit)-#pos)
END
INSERT INTO #returnList
SELECT #stringToSplit
RETURN
END
-- USE THIS PARAMETER TO PASS VALUE
DECLARE #STRING VARCHAR(MAX)
DECLARE #COUNT INT
DECLARE #I INT
DECLARE #COLUMNNAME VARCHAR(MAX)
DECLARE #CREATETABLE VARCHAR(MAX)
DECLARE #INSERT VARCHAR(MAX)
IF OBJECT_ID('TEMPDB..##TEMPTABLE') IS NOT NULL
DROP TABLE ##TEMPTABLE
IF OBJECT_ID('TEMPDB..##RETURNLIST') IS NOT NULL
DROP TABLE ##RETURNLIST
SELECT * INTO ##RETURNLIST FROM dbo.splitstring(#STRING)
select #COUNT = COUNT(*) from ##RETURNLIST
SET #I=0
SET #CREATETABLE = 'CREATE TABLE ##TEMPTABLE ('
WHILE (#COUNT>0)
BEGIN
SET #COLUMNNAME = 'COLUMN'+ CONVERT(varchar(10), #I) + ' VARCHAR(MAX)'
SET #CREATETABLE = #CREATETABLE + #COLUMNNAME
IF(#COUNT<>1)
SET #CREATETABLE = #CREATETABLE + ', '
SET #I = #I+1
SET #COUNT = #COUNT -1;
END
SET #CREATETABLE = #CREATETABLE + ' )'
EXECUTE(#CREATETABLE)
SET #INSERT = 'INSERT INTO ##TEMPTABLE VALUES( '
WHILE (#I>0)
BEGIN
SET #INSERT = #INSERT +''''+ (SELECT NAME FROM ##RETURNLIST WHERE ID = #COUNT+1) +''''
IF(#I<>1)
SET #INSERT = #INSERT + ', '
SET #I = #I-1
SET #COUNT = #COUNT +1;
ENDenter code here
SET #INSERT = #INSERT + ' )'
EXECUTE(#INSERT)
EXECUTE('SELECT * FROM ##TEMPTABLE')
You haven't given any criteria for joining the values together for each of the rows of columns so I've just joined them in descending order. This solution can handle any number of items in the lists but if the number gets too high you may need to use the MAX RECURSION query hint.
DECLARE #strA NVARCHAR(MAX) = 'A1,A2,A3';
DECLARE #strB NVARCHAR(MAX) = 'B1,B2,B3,B4';
DECLARE #strC NVARCHAR(MAX) = 'C1,C2,C3';
WITH stringData AS (
--each group of comma separate values with a group identifier
SELECT 'a' AS grp, #strA AS strng
UNION ALL
SELECT 'b' AS grp, #strB
UNION ALL
SELECT 'c' AS grp, #strC
),
splitStrings AS (
--a recursive CTE to split the comma separated values
SELECT grp, CAST('' AS NVARCHAR(MAX)) AS item,
strng AS cText
FROM stringData
UNION ALL
SELECT grp,
CASE
WHEN CHARINDEX(N',',cText,0)>0 THEN LEFT(cText,CHARINDEX(N',',cText,0)-1) --SUBSTRING(cText,0,CHARINDEX(N',',cText,0))
ELSE cText
END,
RIGHT(cText,LEN(cText)-CHARINDEX(N',',cText,0))
FROM splitStrings
WHERE cText!=item
)
SELECT grp,
item,
ROW_NUMBER() OVER(PARTITION BY grp ORDER BY item) AS rnum
INTO #stringValues --put the results in a temp table so we don't need to execute the recursive CTE more than once
FROM splitStrings
WHERE len(item)>0;
DECLARE #maxNum INT = (SELECT MAX(rnum) FROM #stringValues);
--join the values together
WITH allNums AS (
SELECT 1 AS num
UNION ALL
SELECT num+1
FROM allNums
WHERE num<#maxNum
)
SELECT sa.item AS colA,
sb.item AS colB,
sc.item AS colC
FROM allNums
LEFT JOIN #stringValues AS sa ON sa.rnum=allNums.num AND sa.grp='A'
LEFT JOIN #stringValues AS sb ON sb.rnum=allNums.num AND sb.grp='B'
LEFT JOIN #stringValues AS sc ON sc.rnum=allNums.num AND sc.grp='C'
DROP TABLE #stringValues;

How do you prepend space in a string where Upper Case letter comes or where a space really needed [duplicate]

This question already has answers here:
Finding Uppercase Character then Adding Space
(3 answers)
Closed 8 years ago.
How do you prepends space in a string where Upper Case letter comes or where a space really needed.
The Sample code is:
DECLARE #teams TABLE (Team NVARCHAR(100))
INSERT INTO #teams
SELECT 'TataConsultencyServices'
UNION ALL
SELECT 'TataConsultencyCompany'
UNION ALL
SELECT 'CompanyHumanResource'
Expected Result
Tata Consultency Services
Tata Consultency Company
Company Human Resource
A set based solution:
DECLARE #s NVARCHAR(100);
SET #s = 'CompanyHumanResources';
DECLARE #Idx INT = 1;
WITH CteRecursive
AS
(
SELECT 1 AS Idx,
CONVERT(NVARCHAR(200), #s) AS String
UNION ALL
SELECT src.Idx + src.IsUpper + 1,
CONVERT(NVARCHAR(200),
CASE WHEN src.IsUpper = 1 THEN STUFF(src.String, src.Idx+1, 0, ' ') ELSE src.String END
)
FROM
(
SELECT rec.*,
CASE WHEN SUBSTRING(rec.String, rec.Idx, 1) <> ' ' AND SUBSTRING(rec.String, rec.Idx+1, 1) LIKE '[A-Z]' AND SUBSTRING(rec.String, rec.Idx+1, 1) COLLATE Romanian_CS_AS = UPPER(SUBSTRING(rec.String, rec.Idx+1, 1)) COLLATE Romanian_CS_AS THEN 1 ELSE 0 END AS IsUpper
FROM CteRecursive rec
WHERE rec.Idx + 1 <= LEN(rec.String)
) src
)
SELECT TOP(1) x.String
FROM CteRecursive x
ORDER BY x.Idx DESC;
Results:
String
-----------------------
Company Human Resources
You may surely get some help from this:-
CREATE FUNCTION CaseSensitiveSQLSplitFunction
(
#str nvarchar(max)
)
returns #t table (val nvarchar(max))
as
begin
declare #i int, #j int
select #i = 1, #j = len(#str)
declare #w nvarchar(max)
while #i <= #j
begin
if substring(#str,#i,1) = UPPER(substring(#str,#i,1)) collate Latin1_General_CS_AS
begin
if #w is not null
insert into #t (val) select #w
set #w = substring(#str,#i,1)
end
else
set #w = #w + substring(#str,#i,1)
set #i = #i + 1
end
if #w is not null
insert into #t (val) select #w
return
end
Taking the sample as:-
declare #str nvarchar(max) = N'ThisIsATest'
select * from dbo.CaseSensitiveSQLSplitFunction(#str)
set #str = N'ThisIsASqlServerCaseSensitiveSplitStringFunction'
select * from dbo.CaseSensitiveSQLSplitFunction(#str)
It is now possible to sql concatenate string values in a way from rows to single column value.
We can just use any of the sql concatenation function.
declare #str nvarchar(max) = N'ThisIsATest'
SELECT LTRIM(STUFF((
SELECT ' ' + val FROM dbo.CaseSensitiveSQLSplitFunction(#str) FOR XML PATH('')
), 1, 1, '')) string
set #str = N'ThisIsASqlServerCaseSensitiveSplitStringFunction'
SELECT LTRIM(STUFF((
SELECT ' ' + val FROM dbo.CaseSensitiveSQLSplitFunction(#str) FOR XML PATH('')
), 1, 1, '')) string
WHILE 1 = 1
BEGIN
UPDATE #teams
SET TeamName = STUFF(TeamName, patindex('%[a-z,.][A-Z]%', TeamName COLLATE Latin1_General_BIN) + 1,0,' ')
WHERE patindex('%[a-z,.][A-Z]%', TeamName COLLATE Latin1_General_BIN) > 0
IF ##ROWCOUNT = 0 BREAK
END
UPDATE #teams
SET TeamName = STUFF(TeamName, patindex('%[A-Z][a-z]%', RIGHT(TeamName,LEN(TeamName) -1) COLLATE Latin1_General_BIN) +1 ,0,' ')
WHERE patindex('%[A-Z][a-z]%', TeamName COLLATE Latin1_General_BIN) > 0

SQL Server string substring with d iterations

I have a string:
#TempCol = sigma_x1,sigma_x2,...,sigma_xd,XX,YY,ZZ
I want to get a substring to get the string sigma_x1,sigma_x2,...,sigma_xd.
d is a variable, so it can be 1, 3, 20, ..., etc.
I know the value of d, but what I don't know is how to get the substring of the original string with d terms.
I tried this:
#L = ''
SET #ColumnNo = 0
WHILE #ColumnNo <= #d
BEGIN
SET #L = #L + ' ' + SUBSTRING(#TempCol, 1, CHARINDEX(',',#TempCol)-1 )
SET #TempCol = REPLACE ( #TempCol, LTRIM(RTRIM(#L) ) ,'')
Set #ColumnNo = #ColumnNo + 1
PRINT #L
END
but I do not know how to get the expected result.
DECLARE #TempCol varchar(max), #d int, #p int, #Result varchar(max);
SET #TempCol = 'item1,item2,itemA,itemB,item#,item$';
SET #d = 3;
SET #p = 1;
WHILE #d > 0 AND #p > 0 BEGIN
SET #p = CHARINDEX(',', #TempCol, #p);
IF #p > 0 SET #p = #p + 1;
SET #d = #d - 1;
END;
IF #p = 0
SET #Result = #TempCol
ELSE
SET #Result = SUBSTRING(#TempCol, 1, #p - 2);
SELECT #Result;
Basically, the loop just searches for the final position to cut at. The substring is extracted after the loop.
If you specify too large #d then the result will simply be all of #TempCol, otherwise you get the desired number of items.
What you need is a split function (shown at the bottom).
With SplitItems As
(
Select Position, Value
, Row_Number() Over ( Order By Position ) As ItemNum
From dbo.udf_Split( #TempCol, ',' )
)
Select Value
From SplitItems
Where ItemNum <= #d
If you want the assembled string up to a given point you would simply do:
With SplitItems As
(
Select Position, Value
, Row_Number() Over ( Order By Position ) As ItemNum
From dbo.udf_Split( #TempCol, ',' )
)
Select ',' + Value
From SplitItems
Where ItemNum <= #d
Order By ItemNum
For Xml Path('')
Split function:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Create FUNCTION [dbo].[udf_Split]
(
#DelimitedList nvarchar(max)
, #Delimiter nvarchar(2) = ','
)
RETURNS TABLE
AS
RETURN
(
With CorrectedList As
(
Select Case When Left(#DelimitedList, Len(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
+ #DelimitedList
+ Case When Right(#DelimitedList, Len(#Delimiter)) <> #Delimiter Then #Delimiter Else '' End
As List
, Len(#Delimiter) As DelimiterLen
)
, Numbers As
(
Select TOP( Coalesce(DataLength(#DelimitedList)/2,0) ) Row_Number() Over ( Order By c1.object_id ) As Value
From sys.columns As c1
Cross Join sys.columns As c2
)
Select CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
, Substring (
CL.List
, CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen
, CharIndex(#Delimiter, CL.list, N.Value + 1)
- ( CharIndex(#Delimiter, CL.list, N.Value) + CL.DelimiterLen )
) As Value
From CorrectedList As CL
Cross Join Numbers As N
Where N.Value <= DataLength(CL.List) / 2
And Substring(CL.List, N.Value, CL.DelimiterLen) = #Delimiter
)

Resources