SQL Server string substring with d iterations - sql-server

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
)

Related

order by column based on starting Number(Number may be decimal) in a string in sql server

i have a column named name in my table and example data i have included below
name
-----
1.arun888
2.nikl55555
11.abcd5566
1.123.bhdf
2.767ss777
1.21cdm
and i want to sort the deatils like below
name
----
1.arun888
1.123.bhdf
1.21cdm
2.nikl55555
2.767ss777
11.abcd5566
I have tried many ways but nothing works for me
first method i had used
DECLARE #string varchar(100),
#start int,
#end int,
#len int
SET #string = '66555.12tttthe hollies 12345 Test Ad77dress Dr.'
set #string = replace(#string, ' ' , '')
set #len = len(#string)
set #start = PATINDEX('%[0-9]%',#string)
set #end = PATINDEX('%[^0-9]%',substring(#string, #start, #len))-1
print substring(#string, #start, #end)
but it gives only 66555
but i need
66555.12
second method i had used
CREATE FUNCTION dbo.fn_GetNumeric
(#strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
GO
i have used the above function but it wil return all the numbers from string
example
if string is 12.dddh5555
then it return 125555
so i am stuck here. i hope somebody can help me to find this
Try this code:
DECLARE #t TABLE ( name VARCHAR(20) )
INSERT INTO #t
VALUES ( '1.arun888' ),
( '2.nikl55555' ),
( '11.abcd5566' ),
( '1.123.bhdf' ),
( '2.767ss777' ),
( '1.21cdm' );
WITH cte
AS ( SELECT name ,
SUBSTRING(name, 1, PATINDEX('%[^0-9.]%', name) - 1) d
FROM #t
)
SELECT *
FROM cte
ORDER BY CAST(CASE WHEN RIGHT(d, 1) = '.' THEN SUBSTRING(d, 1, LEN(d) - 1)
WHEN d = '' THEN '0'
ELSE d
END AS DECIMAL(30, 10))
First I select substrings till the first symbol that is not dot or digit. Then just remove last dot and order by the result.
With function:
CREATE FUNCTION dbo.fn_GetNumeric
(
#strAlphaNumeric VARCHAR(256)
)
RETURNS DECIMAL(30, 10)
AS
BEGIN
DECLARE #s1 VARCHAR(256) = SUBSTRING(#strAlphaNumeric, 1,
PATINDEX('%[^0-9.]%',
#strAlphaNumeric) - 1)
RETURN CAST(CASE WHEN RIGHT(#s1, 1) = '.' THEN SUBSTRING(#s1, 1, LEN(#s1) - 1)
WHEN #s1 = '' THEN '0'
ELSE #s1
END AS DECIMAL(30, 10))
END
GO
SELECT * FROM TableName
ORDER BY dbo.fn_GetNumeric(name)

How do I replace non word characters with a dash using TSQL?

How do I replace the characters ~!##$%^&*()_+}{][ in a nvarchar (or varchar) field with a - using TSQL?
you can create user define function for that as given below
CREATE FUNCTION udf_ReplaceSpecialChar
(
#inputString VARCHAR(1000)
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #outputString VARCHAR(1000),
#LENGTH INT,
#index INT,
#char CHAR(1)
SELECT #LENGTH = LEN(#inputString),
#index = 1
WHILE(#index <= #LENGTH)
BEGIN
SET #char = SUBSTRING(#inputString, #index, 1)
IF((ASCII(#char) NOT BETWEEN 65 AND 90) AND (ASCII(#char) NOT BETWEEN 97 AND 122) AND (ASCII(#char) NOT BETWEEN 48 AND 57))
BEGIN
SELECT #inputString = REPLACE(#inputString, #char, '-')
END
SET #index = #index + 1
END
SET #outputString = #inputString
RETURN #outputString
END
SELECT dbo.udf_ReplaceSpecialChar('This()*& is%%#Sample**.>String')
or you should replace each character with '-'
Like
SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE('This()*& is%%#Sample**.>String', ' ', '-'), '*', '-'), '#', '-'), '&', '-'), '(', '-'), ')', '-'), '.', '-'), '>', '-'), '%', '-')
You can use REPLACE function. If it doesn't work in some cases, please give us examples.
May be this code is that you are searching for:
-- Author: Christian d'Heureuse, www.source-code.biz
create function dbo.RemoveSpecialChars (#s varchar(256)) returns varchar(256)
with schemabinding
begin
if #s is null
return null
declare #s2 varchar(256)
set #s2 = ''
declare #l int
set #l = len(#s)
declare #p int
set #p = 1
while #p <= #l begin
declare #c int
set #c = ascii(substring(#s, #p, 1))
if #c between 48 and 57 or #c between 65 and 90 or #c between 97 and 122
set #s2 = #s2 + char(#c)
set #p = #p + 1
end
if len(#s2) = 0
return null
return #s2
end
It removes all characters except 0-9, a-z and A-Z. This function uses ASCII codes of characters to determine this ones which must be removed.
--another one variant
----------------------------------------------------------------------------------------
--better to keep such table in server, very usefull table, especially with indexes
DECLARE #Tally TABLE ( N INT )
DECLARE #i AS INT = 1
WHILE #i != 1000
BEGIN
INSERT INTO #Tally
( N )
VALUES ( #i )
SET #i = #i + 1
END
----------------------------------------------------------------------------------------
DECLARE #String AS VARCHAR(1000) = 'This()*& is%%# **.>another one //&^&*$variant'
----------------------------------------------------------------------------------------
--using #tally - split, using like - remove not required, 'for xml ...' - combine into string
SELECT REPLACE(( SELECT LEFT(SUBSTRING(#String, n, 1000), 1)
FROM #Tally AS T
WHERE SUBSTRING(#String, n, 1000) != ''
AND LEFT(SUBSTRING(#String, n, 1000), 1) LIKE '[A-Za-z0-9 ]'
FOR
XML PATH('')
), ' ', ' ')
--another one variant
------------------------------------------------------------------------------------
--better to keep such table in server, very usefull table, especially with indexes
DECLARE #Tally TABLE ( N INT )
DECLARE #i AS INT = 1
WHILE #i != 1000
BEGIN
INSERT INTO #Tally
( N )
VALUES ( #i )
SET #i = #i + 1
END
------------------------------------------------------------------------------------
DECLARE #String VARCHAR(500) ,
#B VARCHAR(500) = ''
SET #String = 'This()*& is%%# **.>another one //&^&*$variant'
SELECT #B = #B + SUBSTRING(#String, t.N, 1)
FROM #Tally t
WHERE t.N <= DATALENGTH(#String)
AND PATINDEX('[A-Za-z0-9 ]', SUBSTRING(#String, t.N, 1)) > 0
SELECT #B
--------------------------------------------------------------------------------
if you wish use this method like a function then:
Create Tally table with one field PRIMARY KEY (1000 rows, starting from 1 with step 1)
Use code below to create function
Table Tally will be very useful for the split sting, clean string etc., currently this is
the best way to use instead fetch, xml and etc.
--------------------------------------------------------------------------------
CREATE FUNCTION [dbo].[StringClean](
#A VARCHAR(500))
RETURNS VARCHAR(500)
AS
BEGIN
DECLARE #B VARCHAR(500)
SET #B = ''
SELECT #B = #B + SUBSTRING(#A, t.N, 1)
FROM dbo.Tally t
WHERE t.N <= DATALENGTH(#A)
AND PATINDEX('[A-Za-z0-9 ]', SUBSTRING(#A, t.N, 1)) > 0
RETURN #B
END
-------------------------------------------------------------------------------
SELECT dbo.StringClean('This()*& is%%# **.>another one //&^&*$variant')
-------------------------------------------------------------------------------
DECLARE #Tally TABLE ( N INT )
DECLARE #i AS INT = 1
WHILE #i != 1000
BEGIN
INSERT INTO #Tally (N) VALUES (#i)
SET #i = #i + 1
END
--------------------------------------------------------------
DECLARE #String VARCHAR(500)
DECLARE #B VARCHAR(500) = ''
DECLARE #ReplacedChars VARCHAR(50) = '~!##$%^&*()_+}{][<>/.'
SET #String = 'This()*& is%%# **.>another one //&^&*$variant'
SELECT #B = #B + CASE WHEN CHARINDEX(SUBSTRING(#String, t.N, 1), #ReplacedChars) > 0 THEN '-'
ELSE SUBSTRING(#String, t.N, 1) END
FROM #Tally t
WHERE t.N <= DATALENGTH(#String)
SELECT #B

Replace every 2nd instance of character in string with TSQL

I have a field that contains a string of lat/long co-ordinates that define a geofence (polygon). Each is seperated by a comma.
eg: 'lat,long,lat,long,lat,long'
eg: 148.341158,-21.500773,148.341406,-21.504989,148.375136,-21.513174,148.401674,-21.535247,148.418044,-21.532767,148.408867,-21.511685,148.414075,-21.508461,148.36968,-21.432567,148.349094,-21.438768,148.346862,-21.480187,148.341158,-21.500773,
I'd like to use this with the geography type in MSSQL (http://msdn.microsoft.com/en-us/library/bb933971.aspx)
DECLARE #g geography;
SET #g = geography::STPolyFromText('POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))', 4326);
SELECT #g.ToString();
This seems to require: 'lat long, lat long, lat long' ie: no comma between the pair.
I can't change the source data, as it's used by a vendor program. I need to manipulate the string to remove every 1 out of 2 commas, or failing that, get regex working in TSQL
You could use a numbers table (a very handy tool for many purposes, by the way) to find the positions of all the commas, then, using only the odd position numbers, replace the corresponding commas with spaces in a single SELECT statement. Here's what I am talking about:
WITH CTE AS (
SELECT number, rn = ROW_NUMBER() OVER (ORDER BY number)
FROM master.dbo.spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND LEN(#coords)
AND SUBSTRING(#coords, number, 1) = ','
)
SELECT
#coords = STUFF(#coords, number, 1, ' ')
FROM CTE
WHERE rn % 2 = 1
;
In the above query, the numbers table's "part" is "played" by a subset of system table master.dbo.spt_values. The CTE calculates the positions of all the commas in the #coords string, returning the results as a row set. The main SELECT is used an assignment statement. It takes every number in the CTE set and removes the character at the corresponding position in #coords, replacing it with a space character (all with the help of the STUFF function).
You can use this SQL Fiddle demo to play with the query.
This ended up my Solution:
DECLARE #WorkingCoordList VARCHAR(max) = 'some lat,long,lat,long string'
DECLARE #Processed INT = 0
DECLARE #CommaLoc INT
DECLARE #Count INT = 0
WHILE #Processed = 0
BEGIN
SET #CommaLoc = PATINDEX('%,%', #WorkingCoordList)
IF #Count % 2 = 0
BEGIN
SET #WorkingCoordList = STUFF(#WorkingCoordList, #CommaLoc, 1, ' ') --Convert comma to space
END
ELSE
BEGIN
SET #WorkingCoordList = STUFF(#WorkingCoordList, #CommaLoc, 1, '#') -- Convert comma to hash
END
IF #CommaLoc = LEN(#WorkingCoordList)
BEGIN
SET #WorkingCoordList = LEFT(#WorkingCoordList, LEN(#WorkingCoordList) - 1) -- trim trailing ,
SET #WorkingCoordList = RTRIM(LTRIM(REPLACE(#WorkingCoordList, '#', ', '))) -- Convert all the hashes to commas
SET #Processed = 1
END
SET #Count = #Count + 1
END
END
You could roll your own parser like the following. It uses the commas in the string to find all of the lattitude/ longitude values. It concatenates all the values together using the pattern: lat long, lat long, ...
declare #list varchar(max)
declare #result varchar(max)
declare #word varchar(max)
declare #splitOn varchar(1)
declare #wpos int
declare #cpos int
declare #wordCount int
select #list = '148.341158,-21.500773,148.341406,-21.504989,148.375136,-21.513174,148.401674,-21.535247,148.418044,-21.532767,148.408867,-21.511685,148.414075,-21.508461,148.36968,-21.432567,148.349094,-21.438768,148.346862,-21.480187,148.341158,-21.500773,'
select #splitOn = ','
select #result = ''
select #cpos = 0
select #wpos = 1
select #wordCount = 1
while (#cpos <= len(#list))
begin
select #cpos = charindex(#splitOn, #List, #cpos)
if (#cpos < 1) select #cpos = len(#list) + 1
select #word = substring(#list, #wpos, #cpos - #wpos)
select #result = #result + ' ' + #word
if ((#wordCount % 2) = 0 and (#cpos < len(#list))) select #result = #result + ','
select #cpos = #cpos + 1
select #wpos = #cpos
select #wordCount = #wordCount + 1
end
select #result as result
Which produces the following string:
148.341158 -21.500773, 148.341406 -21.504989, 148.375136 -21.513174, 148.401674 -21.535247, 148.418044 -21.532767, 148.408867 -21.511685, 148.414075 -21.508461, 148.36968 -21.432567, 148.349094 -21.438768, 148.346862 -21.480187, 148.341158 -21.500773
I don't know how your regex works but if you preprocess the string with a regex, it might work with a global search and replace like this:
find: ,([^,]*(?:,|$))
replace: '$1' ie. space plus capture group 1
Thanks for the code :-)
I had a slightly different scenario however created a function using "chue x" code to add a character '#' at every 3rd ';'
/*** My select query ***/
SELECT dbo.fn_AddEveryNthItem(a.MyString, ';','#', 3) AS Expr1
FROM dbo.MyTable as a
Function is below
/*** Function to add character for every nth item ***/
Create function dbo.fn_AddEveryNthItem(#list varchar(1000), #splitOn varchar(1), #addChar varchar(1), #EveryNthItem int)
RETURNS VARCHAR(1000)
AS
BEGIN
declare #word varchar(max)
declare #result varchar(max) = ''
declare #wpos int = 1
declare #cpos int = 0
declare #wordCount int =1
while (#cpos <= len(#list))
begin
select #cpos = charindex(#splitOn, #List, #cpos)
if (#cpos < 1) select #cpos = len(#list) + 1
select #word = substring(#list, #wpos, #cpos - #wpos)
select #result = #result + #splitOn + #word
if ((#wordCount % #EveryNthItem) = 0 and (#cpos < len(#list))) select #result = #result + #addChar
select #cpos = #cpos + 1
select #wpos = #cpos
select #wordCount = #wordCount + 1
end
Return #result
end

Replace unicode number between to different delimiters with NCHAR function

I've created a MSSQL Server function which encodes special chars (example: हिन्दीabcde fG#) to the unicode number with "#" and ";" as delimiter. Only very simple chars like "abc" will not be encoded:
declare #position int, #txt nvarchar(max), #output as varchar(max);
set #position=1;
set #txt = N'हिन्दीabcde fG#';
set #output = '';
while #position <= len(#txt)
begin
declare #t int;
select #t=unicode(substring(#txt,#position,1))
--print '&#'+ CONVERT(nvarchar(5),#t)+';'
if ( (#t between 48 and 57) OR (#t between 65 and 90) or (#t between 97 and 122) )
BEGIN
SET #output = #output + CONVERT(nvarchar(5), substring(#txt,#position,1) );
END
else
BEGIN
SET #output = #output + '#'+ CONVERT(nvarchar(5),#t)+';'
END
set #position = #position+1
end
Print #output
The result is:
2361;#2367;#2344;#2381;#2342;#2368;abcde#32;fG#35;
I need it for working with ODBC drivers and to avoid problems with special chars.
But now I need the way back - to decode the encoded chars. Is there any smart solution or will I need at least two loops, the "NCHAR" function ...?
I'll try to build such a function - if it's successfull, I'll post it here :)
You might find this approach a little more appealing. First, create a split function that maintains order:
CREATE FUNCTION dbo.SplitStringsOrdered
(
#List NVARCHAR(MAX),
#delim NVARCHAR(10)
)
RETURNS TABLE
AS
RETURN
(
SELECT rn, v = LTRIM(RTRIM(SUBSTRING(#List, rn,
CHARINDEX(#delim, #List + #delim, rn) - rn)))
FROM
(
SELECT TOP (8000) rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
) AS n
WHERE rn <= LEN(#List)
AND SUBSTRING(#delim + #List, rn, LEN(#delim)) = #delim
);
GO
Usage:
DECLARE #x NVARCHAR(MAX) = N'#2361;#2367;#2344;#2381;'
+ N'#2342;#2368;abcde#32;fG#35;';
-- need one small adjustment to make the string more split-friendly:
SET #x = REPLACE(#x, '#', ';#');
DECLARE #output NVARCHAR(MAX);
SELECT #output = (SELECT
CASE WHEN v LIKE '#%' THEN NCHAR(REPLACE(v, '#', '')) ELSE v END
FROM dbo.SplitStringsOrdered(#x, ';') AS x
ORDER BY rn FOR XML PATH(''),
TYPE).value('./text()[1]','nvarchar(max)');
SELECT #output;
Output:
हिन्दीabcde fG#
I've solved the problem with this query:
declare #position int, #txt nvarchar(max), #output as nvarchar(max), #buffer as varchar(max);
set #position=1;
set #txt = '#2361;#2367;#2344;#2381;#2342;#2368;abcde#32;fG#35;';
set #output = '';
set #buffer = '';
while #position <= len(#txt)
begin
declare #t varchar(max);
select #t=(substring(#txt,#position,1))
if ( len(#buffer) = 0 and #t <> '#' and #t <> ';')
BEGIN
-- Append simple chars, which were not encoded
Print 'Hänge den String ganz normal an den Output: ' + #t
SET #output = #output + #t;
END
ELSE
BEGIN
if ( #t = '#' )
BEGIN
Print 'Raute wurde erkannt: #';
SET #buffer = '#';
END
else if ( #t = ';' )
BEGIN
SET #buffer = REPLACE( #buffer, '#' , '' );
Print 'Umwandeln: ' + #buffer
SET #output = #output + isnull( NCHAR(#buffer) , '');
SET #buffer = '';
END
else
BEGIN
Print 'Ganzzahl an den Buffer anhängen: ' + #t;
SET #buffer = #buffer + #t;
END
END
set #position = #position+1
end
Print #output

How to compare two string elements in 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

Resources