T-SQL split string based on delimiter - sql

I have some data that I would like to split based on a delimiter that may or may not exist.
Example data:
John/Smith
Jane/Doe
Steve
Bob/Johnson
I am using the following code to split this data into First and Last names:
SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM MyTable
The results I would like:
FirstName---LastName
John--------Smith
Jane--------Doe
Steve-------NULL
Bob---------Johnson
This code works just fine as long as all the rows have the anticipated delimiter, but errors out when a row does not:
"Invalid length parameter passed to the LEFT or SUBSTRING function."
How can I re-write this to work properly?

May be this will help you.
SELECT SUBSTRING(myColumn, 1, CASE CHARINDEX('/', myColumn)
WHEN 0
THEN LEN(myColumn)
ELSE CHARINDEX('/', myColumn) - 1
END) AS FirstName
,SUBSTRING(myColumn, CASE CHARINDEX('/', myColumn)
WHEN 0
THEN LEN(myColumn) + 1
ELSE CHARINDEX('/', myColumn) + 1
END, 1000) AS LastName
FROM MyTable

For those looking for answers for SQL Server 2016+. Use the built-in STRING_SPLIT function
Eg:
DECLARE #tags NVARCHAR(400) = 'clothing,road,,touring,bike'
SELECT value
FROM STRING_SPLIT(#tags, ',')
WHERE RTRIM(value) <> '';
Reference: https://msdn.microsoft.com/en-nz/library/mt684588.aspx

Try filtering out the rows that contain strings with the delimiter and work on those only like:
SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM MyTable
WHERE CHARINDEX('/', myColumn) > 0
Or
SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM MyTable
WHERE myColumn LIKE '%/%'

SELECT CASE
WHEN CHARINDEX('/', myColumn, 0) = 0
THEN myColumn
ELSE LEFT(myColumn, CHARINDEX('/', myColumn, 0)-1)
END AS FirstName
,CASE
WHEN CHARINDEX('/', myColumn, 0) = 0
THEN ''
ELSE RIGHT(myColumn, CHARINDEX('/', REVERSE(myColumn), 0)-1)
END AS LastName
FROM MyTable

ALTER FUNCTION [dbo].[split_string](
#delimited NVARCHAR(MAX),
#delimiter NVARCHAR(100)
) RETURNS #t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE #xml XML
SET #xml = N'<t>' + REPLACE(#delimited,#delimiter,'</t><t>') + '</t>'
INSERT INTO #t(val)
SELECT r.value('.','varchar(MAX)') as item
FROM #xml.nodes('/t') as records(r)
RETURN
END

I just wanted to give an alternative way to split a string with multiple delimiters, in case you are using a SQL Server version under 2016.
The general idea is to split out all of the characters in the string, determine the position of the delimiters, then obtain substrings relative to the delimiters. Here is a sample:
-- Sample data
DECLARE #testTable TABLE (
TestString VARCHAR(50)
)
INSERT INTO #testTable VALUES
('Teststring,1,2,3')
,('Test')
DECLARE #delimiter VARCHAR(1) = ','
-- Generate numbers with which we can enumerate
;WITH Numbers AS (
SELECT 1 AS N
UNION ALL
SELECT N + 1
FROM Numbers
WHERE N < 255
),
-- Enumerate letters in the string and select only the delimiters
Letters AS (
SELECT n.N
, SUBSTRING(t.TestString, n.N, 1) AS Letter
, t.TestString
, ROW_NUMBER() OVER ( PARTITION BY t.TestString
ORDER BY n.N
) AS Delimiter_Number
FROM Numbers n
INNER JOIN #testTable t
ON n <= LEN(t.TestString)
WHERE SUBSTRING(t.TestString, n, 1) = #delimiter
UNION
-- Include 0th position to "delimit" the start of the string
SELECT 0
, NULL
, t.TestString
, 0
FROM #testTable t
)
-- Obtain substrings based on delimiter positions
SELECT t.TestString
, ds.Delimiter_Number + 1 AS Position
, SUBSTRING(t.TestString, ds.N + 1, ISNULL(de.N, LEN(t.TestString) + 1) - ds.N - 1) AS Delimited_Substring
FROM #testTable t
LEFT JOIN Letters ds
ON t.TestString = ds.TestString
LEFT JOIN Letters de
ON t.TestString = de.TestString
AND ds.Delimiter_Number + 1 = de.Delimiter_Number
OPTION (MAXRECURSION 0)

The examples above work fine when there is only one delimiter, but it doesn't scale well for multiple delimiters. Note that this will only work for SQL Server 2016 and above.
/*Some Sample Data*/
DECLARE #mytable TABLE ([id] VARCHAR(10), [name] VARCHAR(1000));
INSERT INTO #mytable
VALUES ('1','John/Smith'),('2','Jane/Doe'), ('3','Steve'), ('4','Bob/Johnson')
/*Split based on delimeter*/
SELECT P.id, [1] 'FirstName', [2] 'LastName', [3] 'Col3', [4] 'Col4'
FROM(
SELECT A.id, X1.VALUE, ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY A.id) RN
FROM #mytable A
CROSS APPLY STRING_SPLIT(A.name, '/') X1
) A
PIVOT (MAX(A.[VALUE]) FOR A.RN IN ([1],[2],[3],[4],[5])) P

These all helped me get to this. I am still on 2012 but now have something quick that will allow me to split a string, even if string has varying numbers of delimiters, and grab the nth substring from that string. It's quick too. I know this post is old, but it took me forever to find something so hopefully this will help someone else.
CREATE FUNCTION [dbo].[SplitsByIndex]
(#separator VARCHAR(20) = ' ',
#string VARCHAR(MAX),
#position INT
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #results TABLE
(id INT IDENTITY(1, 1),
chrs VARCHAR(8000)
);
DECLARE #outResult VARCHAR(8000);
WITH X(N)
AS (SELECT 'Table1'
FROM(VALUES(0), (0), (0), (0), (0), (0), (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) T(C)),
Y(N)
AS (SELECT 'Table2'
FROM X A1,
X A2,
X A3,
X A4,
X A5,
X A6,
X A7,
X A8), -- Up to 16^8 = 4 billion
T(N)
AS (SELECT TOP (ISNULL(LEN(#string), 0)) ROW_NUMBER() OVER(
ORDER BY
(
SELECT NULL
)) - 1 N
FROM Y),
Delim(Pos)
AS (SELECT t.N
FROM T
WHERE(SUBSTRING(#string, t.N, LEN(#separator + 'x') - 1) LIKE #separator
OR t.N = 0)),
Separated(value)
AS (SELECT SUBSTRING(#string, d.Pos + LEN(#separator + 'x') - 1, LEAD(d.Pos, 1, 2147483647) OVER(
ORDER BY
(
SELECT NULL
))-d.Pos - LEN(#separator))
FROM Delim d
WHERE #string IS NOT NULL)
INSERT INTO #results(chrs)
SELECT s.value
FROM Separated s
WHERE s.value <> #separator;
SELECT #outResult =
(
SELECT chrs
FROM #results
WHERE id = #position
);
RETURN #outResult;
END;
This can be used like this:
SELECT [dbo].[SplitsByIndex](' ',fieldname,2)
from tablename

I would protect the substring operation by always appending a delimiter to the test strings. This makes the parsing much simpler. Your code may now rely on finding the right pattern, and not need to cope with special cases.
SELECT SUBSTRING(myColumn + '/', 1, CHARINDEX('/', myColumn)-1) AS FirstName,
SUBSTRING(myColumn + '/', CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM MyTable
It eliminates edge cases and conditionals and cases.
Always add an extra delimiter at the end, then the challenge case is no problem.

Related

Add character in front and at the end of each character

In SQL I want to add 0 in front and , at the end of each character.
Example: A30F1 -> 0A,03,00,0F,01
I don't want to use cursor if possible.
Thanks!
EIDT:
I apologize for not asking the most appropriate question at the beginning.
In short, I have a table and for each value in the column name I have to convert it to the desired format. For example, we have a #Temp table:
CREATE TABLE #Temp (id INT, name VARCHAR(25))
INSERT INTO #Temp VALUES (1, 'A30F1'), (2, 'B51R9'), (3, 'L1721')
SELECT * FROM #Temp
One method would be to use a Tally to split the string into it's individual characters, and then use concatenation to add the 0 to the start, and STRING_AGG to comma delimit the results:
DECLARE #YourValue varchar(5) = 'A30F1';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (LEN(#YourValue))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --Up to 100 characters, add more cross joins for more characters
SELECT STRING_AGG(CONCAT('0',SS.C),',') WITHIN GROUP (ORDER BY T.I) AS NewString
FROM (VALUES(#YourValue))V(YourValue)
CROSS JOIN Tally T
CROSS APPLY (VALUES(SUBSTRING(V.YourValue,T.I,1)))SS(C);
It appears this is meant to be against a table, not a single value. This needs, however, very few changes to work against a table:
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT MAX(LEN(YourColumn)) FROM dbo.YourTable)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2) --Up to 100 characters, add more cross joins for more characters
SELECT STRING_AGG(CONCAT('0',SS.C),',') WITHIN GROUP (ORDER BY T.I) AS NewString
FROM dbo.YourTable YT
JOIN Tally T ON LEN(YT.YourColumn) >= T.I
CROSS APPLY (VALUES(SUBSTRING(YT.YourColumn,T.I,1)))SS(C)
GROUP BY YT.YourColumn;
db<>fiddle
I solved the simplest possible with a few variables, WHILE and SUBSTRING
DECLARE #var VARCHAR(20) = 'A30F1', #i INT = 1, #res NVARCHAR(20)
WHILE (#i <= LEN(#var))
BEGIN
SET #res = #res + '0' + SUBSTRING(#var, #i, 1) + ','
SET #i = #i + 1
END
SELECT LEFT(#res, LEN(#res) - 1) output
Check demo on DB<>FIDDLE.
Original answer:
A recursive CTE and a STRING_AGG() call is also an option (SQL Server 2017+ is needed):
DECLARE #text varchar(max) = 'A30F1';
WITH rCTE AS
(
SELECT 1 AS CharacterPosition, SUBSTRING(#text, 1, 1) AS Character
UNION ALL
SELECT CharacterPosition + 1, SUBSTRING(#text, CharacterPosition + 1, 1)
FROM rCTE
WHERE CharacterPosition < LEN(#text)
)
SELECT STRING_AGG('0' + Character, ',') WITHIN GROUP (ORDER BY CharacterPosition)
FROM rCTE
OPTION (MAXRECURSION 0);
Update:
You need a different statement, if the names are stored in a table, again using recursion and STRING_AGG():
Table:
CREATE TABLE #Temp (id INT, name VARCHAR(25))
INSERT INTO #Temp VALUES (1, 'A30F1'), (2, 'B51R9'), (3, 'L1721')
Statement:
; WITH rCTE AS (
SELECT
t.id AS id,
LEFT(t.name, 1) AS Character,
STUFF(t.name, 1, 1, '') AS CharactersRemaining,
1 AS CharacterPosition
FROM #Temp t
UNION ALL
SELECT
r.id,
LEFT(r.CharactersRemaining, 1),
STUFF(r.CharactersRemaining, 1, 1, ''),
CharacterPosition + 1
FROM rCTE r
WHERE LEN(r.CharactersRemaining) > 0
)
SELECT
id,
STRING_AGG('0' + Character, ',') WITHIN GROUP (ORDER BY CharacterPosition) AS name
FROM rCTE
GROUP BY id
OPTION (MAXRECURSION 0);
Result:
id name
1 0A,03,00,0F,01
2 0B,05,01,0R,09
3 0L,01,07,02,01
If you are only applying this to English alphabet characters and digits as in your example you could do this.
CREATE TABLE #Temp (id INT, name VARCHAR(25))
INSERT INTO #Temp VALUES (1, 'A30F1'), (2, 'B51R9'), (3, 'L1721'), (4, 'A')
SELECT SUBSTRING(REPLACE(
0x00 + CAST(CAST(name AS NVARCHAR(25)) AS BINARY(50)), CHAR(0), '0,')
, 3
, LEN(name) * 3 - 1)
FROM #Temp
returns
0A,03,00,0F,01
0B,05,01,0R,09
0L,01,07,02,01
0A
This takes advantage of the fact that the binary representation of the nvarchar and varchar is the same for this limited character set except for padding out with 0x00
'A30F1' -> 0x4133304631
N'A30F1' -> 0x41003300300046003100

Best way to pad section of this string with 0s

This is 2 examples of what the string currently look like:
6731-121-1
9552-3-1
This is what I want to pad them to look like
0006731-121-1
0009552-003-1
So I want them to be padded with 7 zeroes before the first '-' then 3 zeroes between the first and second '-'
What would be the best way to accomplish this in SQL SELECT statement.
SELECT RIGHT('0000000'
+ ISNULL(
LEFT(OE.exception_id, CHARINDEX('-', OE.exception_id)
- 1) ,
''
) ,7) + '-'
+ SUBSTRING(OE.exception_id, CHARINDEX('-', ( OE.exception_id )), 10) exception_id
ParseName() could be an option here
Example
Declare #YourTable Table ([YourCol] varchar(50))
Insert Into #YourTable Values
('6731-121-1')
,('9552-3-1')
Select *
,NewVal = right('0000000'+parsename(replace(YourCol,'-','.'),3),7)
+'-'
+right('000'+parsename(replace(YourCol,'-','.'),2),3)
+'-'
+parsename(replace(YourCol,'-','.'),1)
From #YourTable
Returns
YourCol NewVal
6731-121-1 0006731-121-1
9552-3-1 0009552-003-1
In situations with more than 3 periods
Example: '1.2.3.4.5'
Or any value is empty
3 examples: '1..3', '1.2.3.', '.2'
Parsename will return null for all values. You will need to split the column using a different method.
Here is an alternative to parsename:
DECLARE #table table(col varchar(100))
INSERT #table values('6731-121-1'),('9552-3-1')
SELECT
col,
REPLICATE('0', 8-x) + STUFF(col, x+1, 0,REPLICATE('0', 4 - (y-x))) newcol
FROM #table
CROSS APPLY
(SELECT CHARINDEX('-', col) x) x
CROSS APPLY
(SELECT CHARINDEX('-', col + '-', x+1) y) y
col newcol
6731-121-1 0006731-121-1
9552-3-1 0009552-003-1

Select substring up until second underscore in SQL

I have strings like this:
FOO_BAR_3423423_dsadsa.doc
BAZ_BAZzz_dsadsa.nox
The number if _ can differ, but I need to select always up untill the second _:
FOO_BAR
BAZzz_BAZ
I am able to select until the first _:
SUBSTRING ([COLUMN], 0, CHARINDEX('/', [COLUMN], 0))
But how to expand this to go up to the second underscore?
You can use the Cross Apply the following query will give you the indexes with the data.
declare #T table
(
Name_Level varchar(25)
)
insert into #T values
('FOO_BAR_3423423_dsadsa'),
('BAZ_BAZzz_dsadsa'),
select SUBSTRING(Name_Level,0,p2.pos) As Data,p1.Pos as firstOccurance,p2.pos As secondOccurance
from #T
cross apply (select (charindex('_', Name_Level))) as P1(Pos)
cross apply (select (charindex('_', Name_Level, P1.Pos+1))) as P2(Pos)
Result:
-------------------------
FOO_BAR 4 8
BAZ_BAZzz 4 10
If you want to get the next index just add one more CrossApply and it will give you the next index of _.
Something like:
SUBSTRING ([COLUMN], 0, CHARINDEX('/', [COLUMN], CHARINDEX('/', [COLUMN], 0) + 1))
This won't work if there is less than two though.
Use while loop. Try this.
DECLARE #str VARCHAR(5000)='FOO_BAR_3423423_dsadsa.doc',
#temp INT=1,
#cnt INT=0,
#result VARCHAR(5000)='',
#intr VARCHAR(50)=''
WHILE #temp <= Len(#str)
BEGIN
SELECT #intr = Substring(#str, #temp, 1)
SET #cnt += (SELECT CASE WHEN #intr = '_' THEN 1 ELSE 0 END)
SET #result+=#intr
IF #cnt = 2
BREAK
SET #temp+=1
END
SELECT SELECT left(#result ,len(#result)-1)

Split the query string with repeatative special characters using SQL

This is my String
Declare #qstr as varchar(max)='hireteammember.aspx?empemail=kuldeep#asselsolutions.com&empid=376&empname=kuldeep&adminname=TMA1&term=5&teamid=161&contactid=614¥1&WP=100¥5¥Months&Amt=500&DueDay=5&StrDt=12/31/2013&MemCatg=Employees&StrTm=21:05&PlnHrs=5&WrkDays=true¥true¥true¥true¥true¥false¥false'
I want to extract the values of empid,empname,adminname,term,teamid,contactid,WP,Months,Dueday,StrDt,MemCatgmStrTm,PlnHrs,WrkDays and assign them to new variables
I have used
select ( SUBSTRING(#qstr,CHARINDEX('=',#qstr)+1,CHARINDEX('&',#qstr)-CHARINDEX('=',#qstr)-1)))
but only getting the 'empemail' , for the next occurance of special char '&' , not able to get the values of further terms , if i am using '&' in spite of '=' .
Help me to split the whole string
How about using XML to split the values into rows, and then splitting them into columns.
Something like
Declare #qstr as varchar(max)='hireteammember.aspx?empemail=kuldeep#asselsolutions.com&empid=376&empname=kuldeep&adminname=TMA1&term=5&teamid=161&contactid=614¥1&WP=100¥5¥Months&Amt=500&DueDay=5&StrDt=12/31/2013&MemCatg=Employees&StrTm=21:05&PlnHrs=5&WrkDays=true¥true¥true¥true¥true¥false¥false'
DECLARe #str VARCHAR(MAX) = SUBSTRING(#qstr,CHARINDEX('?',#qstr,0) + 1, LEN(#qstr)-CHARINDEX('?',#qstr,0))
DECLARE #xml XML
SELECT #xml = CAST('<d>' + REPLACE(#str, '&', '</d><d>') + '</d>' AS XML)
;WITH Vals AS (
SELECT T.split.value('.', 'nvarchar(max)') AS data
FROM #xml.nodes('/d') T(split)
)
SELECT LEFT(data,CHARINDEX('=',data,0) - 1),
RIGHT(data,LEN(data) - CHARINDEX('=',data,0))
FROM Vals
SQL Fiddle DEMO
CREATE FUNCTION dbo.SplitQueryString (#s varchar(8000))
RETURNS table
AS
RETURN (
WITH splitter_cte AS (
SELECT CHARINDEX('&', #s) as pos, 0 as lastPos
UNION ALL
SELECT CHARINDEX('&', #s, pos + 1), pos
FROM splitter_cte
WHERE pos > 0
),
pair_cte AS (
SELECT chunk,
CHARINDEX('=', chunk) as pos
FROM (
SELECT SUBSTRING(#s, lastPos + 1,
case when pos = 0 then 80000
else pos - lastPos -1 end) as chunk
FROM splitter_cte) as t1
)
SELECT substring(chunk, 0, pos) as keyName,
substring(chunk, pos+1, 8000) as keyValue
FROM pair_cte
)
GO
declare #queryString varchar(2048)
set #queryString = 'foo=bar&temp=baz&key=value';
SELECT *
FROM dbo.SplitQueryString(#queryString)
OPTION(MAXRECURSION 0);
when run produces the following output.
keyName keyValue
------- --------
foo bar
temp baz
key value
(3 row(s) affected)
I believe that this will do exactly what you are asking.
SQL FIDDLE DEMO
If the order of the values in the html string remains same i would suggest using the whole string name like
select ( SUBSTRING(#qstr,CHARINDEX('empemail=',#qstr)+1,CHARINDEX('&empid=',#qstr)-CHARINDEX('empemail=',#qstr)-1)))
If you are still looking for nth occurance then refer to this link
Declare #qstr as varchar(max)='hireteammember.aspx?empemail=kuldeep#asselsolutions.com&empid=376&empname=kuldeep&adminname=TMA1&term=5&teamid=161&contactid=614¥1&WP=100¥5¥Months&Amt=500&DueDay=5&StrDt=12/31/2013&MemCatg=Employees&StrTm=21:05&PlnHrs=5&WrkDays=true¥true¥true¥true¥true¥false¥false'
(select ( SUBSTRING(#qstr,CHARINDEX('&empname=',#qstr)+1,CHARINDEX('&adminname=',#qstr)-CHARINDEX('&empname=',#qstr)-1)))
(select ( SUBSTRING(#qstr,CHARINDEX('?empemail=',#qstr)+1,CHARINDEX('&empid=',#qstr)-CHARINDEX('?empemail=',#qstr)-1)))
like this i have splitted and updated The whole string. Thank you All for your answers, Your answers Helped me to solve this

Find position of delimited character in a String (SQL Server)

I have a string Variable
test=HARIA|123|MALE|STUDENT|HOUSEWIFE
i am using | as delimited character. if i want to extract data from 2nd occurence of pipe till 3rd occurrence. i need to get 'MALE' from above string.
any help appreciated
Untested
SELECT
SUBSTRING (
#test,
CHARINDEX('|', #test, CHARINDEX('|', #test) + 1) + 1,
CHARINDEX('|', #test, CHARINDEX('|', #test, CHARINDEX('|', #test) + 1) + 1) - 1
)
A nicer way would be split the string into a table, and use ROW_NUMBER() to extract the 3rd element. Based on this Arrays and Lists in SQL Server
DECLARE #test varchar(100) = 'HARIA|123|MALE|STUDENT|HOUSEWIFE'
SELECT TOP 8000
Num
INTO
#Number
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY c1.object_id) AS Num
FROM
sys.columns c1, sys.columns c2, sys.columns c3
) N
SELECT
ROW_NUMBER() OVER (ORDER BY Num) AS Rank,
LTRIM(RTRIM(SUBSTRING(#test,
Num,
CHARINDEX('|', #test + '|', Num) - Num
))) AS Value
FROM
#Number
WHERE
Num <= LEN (#test)
AND
SUBSTRING('|' + #test, Num, 1) = '|'
DROP TABLE #Number
Try this
Solution 1:(Using a number table)
declare #str varchar(1000)
set #str ='HARIA|123|MALE|STUDENT|HOUSEWIFE'
--Creating a number table
;with numcte as(
select 1 as rn union all select rn+1 from numcte where rn<LEN(#str)),
--Get the position of the "|" charecters
GetDelimitedCharPos as(
select ROW_NUMBER() over(order by getdate()) seq, rn,delimitedcharpos
from numcte
cross apply(select SUBSTRING(#str,rn,1)delimitedcharpos) X where delimitedcharpos = '|')
--Applying the formula SUBSTRING(#str,startseq + 1,endseq-startseq + 1)
-- i.e. SUBSTRING(#str,11,15-11) in this case
select top 1 SUBSTRING(
#str
,(select top 1 rn+1 from GetDelimitedCharPos where seq =2)
,(select top 1 rn from GetDelimitedCharPos where seq =3) -
(select top 1 rn+1 from GetDelimitedCharPos where seq =2)
) DesiredResult
from GetDelimitedCharPos
Solution 2:(Using XQuery)
DECLARE #xml as xml,#str as varchar(100),#delimiter as varchar(10)
SET #str='HARIA|123|MALE|STUDENT|HOUSEWIFE'
SET #xml = cast(('<X>'+replace(#str,'|' ,'</X><X>')+'</X>') as xml)
SELECT ShrededData as DesiredResult FROM(
SELECT
ROW_NUMBER() over(order by getdate()) rn
,N.value('.', 'varchar(10)') as ShrededData FROM #xml.nodes('X') as T(N))X
WHERE X.rn = 3 -- Specifying the destination sequence value(here 3)
Output(in both the cases)
DesiredResult
MALE
I found this. Using a t-Sql for loop. Good reference of syntax, too.