extract all decimal value from a string in sql server - sql

I want to extract all decimal values from a string:
'1.1aa' = 1.1,
'-1.1al3' = -1.13,
' -' = 0
'21d.2 d .3-d' = 21.23
What will be the query to extract this output?
DECLARE #Col VARCHAR(100)='-c 43.f4gh57t';
While (PATINDEX('%[^0-9.-]%', #Col) > 0)
begin
SET #Col = STUFF(#Col, PATINDEX('%[^-0-9.]%', #Col), 1, '');
end
SELECT CAST(#Col AS DECIMAL(18, 2));
I have written this query but it is not working with these values:
' -',
'21d.2 d .3-d'

DECLARE #Col VARCHAR(100)= '--A12345-..6789-.';
While (PATINDEX('%[^0-9.-]%', #Col) > 0)
begin
SET #Col = STUFF(#Col, PATINDEX('%[^-0-9.]%', #Col), 1, '');
end
--remove all hyphens but keep the first one (if first char with numbers following)
select #Col = case when #Col like '-%[0-9]%' then '-' else '' end + replace(#Col, '-', '')
where #Col like '%-%';
--remove all dots but keep the first one (if followed by numbers)
select #Col = stuff(replace(#Col, '.', '')+' ', charindex('.', #Col), 0, case when #Col like '%.%[0-9]%' then '.' else '' end)
where #Col like '%.%';
select #col as _col;
SELECT CAST(case when #col = '' then '0' else #col end AS DECIMAL(20,10)) as _decimal;

You could do this with Tally, though if you have multiple '.' characters or a '-' in the middle of the string it will fail on conversion:
DECLARE #Value varchar(100) = '-c 43.f4gh57t';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (LEN(#Value))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2),
Chars AS(
SELECT T.I,
SUBSTRING(#Value,T.I,1) AS C
FROM Tally T)
SELECT TRY_CONVERT(decimal(25,10),STRING_AGG(C.C,'') WITHIN GROUP (ORDER BY C.I)) AS Number
FROM Chars C
WHERE C.C LIKE '[0-9.-]';
If you're using an older version of SQL Server, you'll need to use the "old" FOR XML PATH (and STUFF) technique instead of STRING_AGG.
Version 2: This should eliminate the errors I describe above:
DECLARE #Value varchar(100) = '-c 4-3.f4gh.57t';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (LEN(#Value))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2),
Chars AS(
SELECT T.I,
SUBSTRING(#Value,T.I,1) AS C
FROM Tally T),
RNs AS(
SELECT C.C,
ROW_NUMBER() OVER (ORDER BY C.I) AS RN,
ROW_NUMBER() OVER (PARTITION BY C.C ORDER BY C.I) AS cRN
FROM Chars C
WHERE C.C LIKE '[0-9.-]')
SELECT TRY_CONVERT(decimal(25,10),STRING_AGG(V.C,'') WITHIN GROUP (ORDER BY R.RN)) AS Number
FROM RNs R
CROSS APPLY (VALUES(CASE R.C WHEN '-' THEN CASE R.RN WHEN 1 THEN R.C END
WHEN '.' THEN CASE R.cRN WHEN 1 THEN R.C END
ELSE R.C
END))V(C);

Related

How to replace anything between 2 specific characters in SQL Server

I'm trying to replace anything between 2 specific characters in a string that contains multiples of those 2 caracters. Take it as a csv format.
Here an example of what i got as data in that field:
0001, ABCD1234;0002, EFGH432562;0003, IJKL1345hsth;...
What I need to retreive from it is all parts before the ',' but not what are between ',' and ';'
I tried with those formula but no success
SELECT REPLACE(fieldname, ',[A-Z];', ' ') FROM ...
or
SELECT REPLACE(fieldname, ',*;', ' ') FROM ...
I need to get
0001 0002 0003
Is there a way to achieve that?
You can CROSS APPLY to a STRING_SPLIT that uses STRING_AGG (since Sql Server 2017) to stick the numbers back together.
select id, codes
from your_table
cross apply (
select string_agg(left(value, patindex('%_,%', value)), ' ') as codes
from string_split(fieldname, ';') s
where value like '%_,%'
) ca;
GO
id
codes
1
0001 0002 0003
Demo on db<>fiddle here
Extra
Here is a version that also works in Sql Server 2014.
Inspired by the research from #AaronBertrand
The UDF uses a recursive CTE to split the string.
And the FOR XML trick is used to stick the numbers back together.
CREATE FUNCTION dbo.fnString_Split
(
#str nvarchar(4000),
#delim nchar(1)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
WITH RCTE AS (
SELECT
1 AS ordinal
, ISNULL(NULLIF(CHARINDEX(#delim, #str),0), LEN(#str)) AS pos
, LEFT(#str, ISNULL(NULLIF(CHARINDEX(#delim, #str),0)-1, LEN(#str))) AS value
UNION ALL
SELECT
ordinal+1
, ISNULL(NULLIF(CHARINDEX(#delim, #str, pos+1), 0), LEN(#str))
, SUBSTRING(#str, pos+1, ISNULL(NULLIF(CHARINDEX(#delim, #str, pos+1),0)-pos-1, LEN(#str)-pos ))
FROM RCTE
WHERE pos < LEN(#str)
)
SELECT ordinal, value
FROM RCTE
);
SELECT id, codes
FROM your_table
CROSS APPLY (
SELECT RTRIM((
SELECT LEFT(value, PATINDEX('%_,%', value))+' '
FROM dbo.fnString_Split(fieldname, ';') AS spl
WHERE value LIKE '%_,%'
ORDER BY ordinal
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)')
) AS codes
) ca
OPTION (MAXRECURSION 250);
id
codes
1
0001 0002 0003
Demo on db<>fiddle here
Alternative version of the UDF (no recursion)
CREATE FUNCTION dbo.fnString_Split
(
#str NVARCHAR(4000),
#delim NCHAR(1)
)
RETURNS #tbl TABLE (ordinal INT, value NVARCHAR(4000))
WITH SCHEMABINDING
AS
BEGIN
DECLARE #value NVARCHAR(4000)
, #pos INT = 0
, #ordinal INT = 0;
WHILE (LEN(#str) > 0)
BEGIN
SET #ordinal += 1;
SET #pos = ISNULL(NULLIF(CHARINDEX(#delim, #str),0), LEN(#str)+1);
SET #value = LEFT(#str, #pos-1);
SET #str = SUBSTRING(#str, #pos+1, LEN(#str));
INSERT INTO #tbl (ordinal, value)
VALUES (#ordinal, #value);
END;
RETURN;
END;
If you're on SQL Server 2017 and don't need a guarantee that the order will be maintained, then LukStorms' answer is perfectly adequate.
However, if you:
care about an order guarantee; or,
are on an older version than 2017 (and can't use STRING_AGG); or,
are on an even older version than 2016 or are in an older compatibility level (and can't use STRING_SPLIT):
Here's an ordered split function that can help (it's long and ugly but you only have to create it once):
CREATE FUNCTION dbo.SplitOrdered
(
#list nvarchar(max),
#delim nvarchar(10)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
WITH w(n) AS (SELECT 0 FROM (VALUES (0),(0),(0),(0)) w(n)),
k(n) AS (SELECT 0 FROM w a, w b),
r(n) AS (SELECT 0 FROM k a, k b, k c, k d, k e, k f, k g, k h),
p(n) AS (SELECT TOP (COALESCE(LEN(#list), 0))
ROW_NUMBER() OVER (ORDER BY ##SPID) -1 FROM r),
spots(p) AS
(
SELECT n FROM p
WHERE (SUBSTRING(#list, n, LEN(#delim + 'x') - 1) LIKE #delim OR n = 0)
),
parts(p,val) AS
(
SELECT p, SUBSTRING(#list, p + LEN(#delim + 'x') - 1,
LEAD(p, 1, 2147483647) OVER (ORDER BY p) - p - LEN(#delim))
FROM spots AS s
)
SELECT listpos = ROW_NUMBER() OVER (ORDER BY p),
Item = LTRIM(RTRIM(val))
FROM parts
);
Then the query can become:
;WITH x AS
(
SELECT id, listpos,
codes = LEFT(Item, COALESCE(NULLIF(CHARINDEX(',', Item),0),1)-1)
FROM dbo.your_table
CROSS APPLY dbo.SplitOrdered(fieldname, ';') AS c
)
SELECT id, codes = (
(SELECT x2.codes + ' '
FROM x AS x2
WHERE x2.id = x.id
ORDER BY x2.listpos
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)')
)
FROM x GROUP BY id;
Example borrowing from LukStorms' db<>fiddle
Note that, in addition to guaranteeing order and being backward compatible (well, only back so many versions), it also ignores garbage data, e.g. try:
0001, ABCD1234;0002 but no comma

sql prefix with numbers

In my select I have multiple dates in one rows, divided by comma.
Main select:
SELECT DISTINCT p.IDVazniZaznam,
stuff(
(
SELECT ','+ CONVERT(VARCHAR,DatumCasZacatku, 22) FROM HVZHlavicka_Prestavka WHERE IDVazniZaznam = p.IDVazniZaznam FOR XML PATH('')
),1,1,'') As DatumCasZacatku,
stuff(
(
SELECT ','+ CONVERT(VARCHAR,DatumCasUkonceni, 22) FROM HVZHlavicka_Prestavka WHERE IDVazniZaznam = p.IDVazniZaznam FOR XML PATH('')
),1,1,'') AS DatumCasUkonceni
FROM (SELECT DISTINCT IDVazniZaznam, DatumCasUkonceni, DatumCasZacatku FROM HVZHlavicka_Prestavka ) p
Like this:
12/04/19 7:45:00 AM,12/04/19 8:00:02 AM
What I need to do is something like that:
1: 12/04/19 7:45:00 AM, 2: 12/04/19 8:00:02 AM
Im not sure if its called prefix, but I think it is. I do not want to put it manually, but I wanna generate it automatically. First date will be number 1, second date number 2 etc.
Its that even possible in SQL?
You can use logic from the below code-
DECLARE #text VARCHAR(MAX) = '12/04/19 7:45:00 AM,12/04/19 8:00:02 AM'
DECLARE #remaining_text VARCHAR(MAX) = #text
DECLARE #new_text VARCHAR(MAX) = ''
DECLARE #CommaIndex INT
DECLARE #Count INT = 1
SET #CommaIndex = CHARINDEX(',',#remaining_text,0)
IF #CommaIndex = 0
BEGIN
SET #new_text = '1: ' + #text
END
ELSE
BEGIN
WHILE #CommaIndex > 0
BEGIN
SET #new_text = #new_text+ ' '+CAST(#Count AS VARCHAR)+': ' + LEFT(#remaining_text,CHARINDEX(',',#remaining_text,0))
SET #remaining_text = RIGHT(#remaining_text,LEN(#remaining_text)-CHARINDEX(',',#remaining_text,0))
SET #CommaIndex = CHARINDEX(',',#remaining_text,0)
SET #Count = #Count + 1
END
END
IF CHARINDEX(',',#text,0) > 0
BEGIN
SET #new_text = #new_text + ' '+CAST(#Count AS VARCHAR)+': ' + #remaining_text
END
SELECT #new_text,#remaining_text
Output is-
1: 12/04/19 7:45:00 AM, 2: 12/04/19 8:00:02 AM
You can use STRING_AGG(), ROW_NUMBER() OVER (ORDER BY ..), STRING_SPLIT() and CONCAT() functions together ( STRING_AGG() works for SQL Server 2017+ ).
In the first step we're splitting the string by comma delimiters in the subquery, and then concatenating those substrings through use of STRING_AGG() :
DECLARE #DatumCasUkonceni NVARCHAR(1000) = '12/04/19 7:45:00 AM,12/04/19 8:00:02 AM';
SELECT STRING_AGG(q.str, ',' ) as "Result"
FROM
(
SELECT CONCAT( ROW_NUMBER() OVER (ORDER BY #DatumCasUkonceni), ' : ',
value ) as str
FROM STRING_SPLIT(#DatumCasUkonceni, ',')
) q
Demo
If STRING_AGG is available to your version of MS Sql Server (2017+), then something like this should do the job.
SELECT IDVazniZaznam
, STRING_AGG(CONCAT(rn,': ',DtStrCasZacatku),', ') AS DatumCasZacatku
, STRING_AGG(CONCAT(rn,': ',DtStrUkonceni),', ') AS DatumCasUkonceni
FROM
(
SELECT DISTINCT IDVazniZaznam
, CONVERT(VARCHAR,DatumCasZacatku, 22) AS DtStrCasZacatku
, CONVERT(VARCHAR,DatumCasUkonceni,22) AS DtStrUkonceni
, ROW_NUMBER() OVER (PARTITION BY IDVazniZaznam ORDER BY DatumCasZacatku, DatumCasUkonceni) AS rn
FROM HVZHlavicka_Prestavka
) q
GROUP BY IDVazniZaznam;
And this will also work in MS Sql Server 2012
WITH CTE AS
(
SELECT DISTINCT IDVazniZaznam
, DatumCasZacatku
, DatumCasUkonceni
, ROW_NUMBER() OVER (PARTITION BY IDVazniZaznam ORDER BY DatumCasUkonceni, DatumCasZacatku) AS rn
FROM HVZHlavicka_Prestavka
)
SELECT q.IDVazniZaznam
, STUFF(a1.DatumCasZacatku,1,2,'') AS DatumCasZacatku
, STUFF(a2.DatumCasUkonceni,1,2,'') AS DatumCasUkonceni
FROM
(
SELECT IDVazniZaznam
FROM CTE
GROUP BY IDVazniZaznam
) AS q
OUTER APPLY
(
SELECT CONCAT(', ',rn,': ', CONVERT(VARCHAR,DatumCasZacatku, 22))
FROM CTE c
WHERE c.IDVazniZaznam = q.IDVazniZaznam
FOR XML PATH ('')
) a1(DatumCasZacatku)
OUTER APPLY
(
SELECT CONCAT(', ',rn,': ', CONVERT(VARCHAR,DatumCasUkonceni,22))
FROM CTE c
WHERE c.IDVazniZaznam = q.IDVazniZaznam
FOR XML PATH ('')
) a2(DatumCasUkonceni);
Test for both on db<>fiddle here

Replace the even characters to upper case and the remaining characters to lower case

Is there an SQL query to replace the even characters to upper case and the remaining characters to lower case in a string?
For example if the string is 'sagar' the result should be like
sAgAr
What would be the appropriate solution for this?
I can't resist answering. This seems like such a natural for a recursive CTE:
with t as (
select 'abcdef' as str
),
cte as (
select cast(lower(str) as varchar(max)) as str, 1 as pos
from t
union all
select stuff(str, pos + 1, 1,
(case when pos % 2 = 1 then upper(substring(str, pos + 1, 1))
else lower(substring(str, pos + 1, 1))
end)
) as str, 1 + pos
from cte
where pos < len(str)
)
select top (1) *
from cte
order by pos desc;
Written the below code and it works fine
Tested on Master DB
declare #name nvarchar(50)
declare #i int
set #i=1
set #name='sagar'
while(#i<=LEN(#name))
begin
if(#i%2=0)
begin
print Upper(SUBSTRING(#name,#i,1))
set #i=#i+1
end
else
begin
print Lower(SUBSTRING(#name,#i,1))
set #i=#i+1
end
end
Give the name of your own choice while setting the #name parameter and you can get the required result
Using a tally table...
declare #table table ([name] varchar(64))
insert into #table
values
('sAgAr')
,('abcdefghijk')
,('LMNOPQ')
;WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select
t.[name]
,lower(left(t.[name],1))
+
STUFF((
SELECT '' + case
when c2.N%2 = 0 then upper(substring(t2.[name],c2.N,1))
else lower(substring(t2.[name],c2.N,1))
end
FROM #table t2
cross apply cteTally c2
where
len(t2.[name]) >= c2.N
and t2.name = t.name
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
from
#table t
This is by splitting into rows and recreating strings again:
declare #test table ([value] nvarchar(20))
insert into #test values ('sagar'), ('Blueprint'), ('turtLe')
;with cte as (
select [value]
, num
, iif(num % 2 = 0, upper(substring([value], num, 1)), lower(substring([value], num, 1))) as [char]
from #test
cross join (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)) numbers(num) --add more for > 12 characters
where num <= len([Value]))
select distinct [Value], [CaseApplied] = STUFF(( SELECT '' + [char]
FROM cte AS c
WHERE c.[value]= cte.value
FOR XML PATH('')
), 1, 0, '')
from cte
Here's one way:
DECLARE #mystringLOW varchar(100) = 'sagar'
,#pos int = 2
WHILE #pos <= LEN(#mystringLOW)
BEGIN
SET #mystringLOW = (SELECT STUFF(#mystringLOW, #pos, 1, UPPER(SUBSTRING(#mystringLOW, #pos, 1))))
SET #pos += 2
END
SELECT #mystringLOW AS [my answer]
Produces:
my answer
---------
sAgAr

How to get first character beside underscore for a given string

input:
string
'abc_def_ghk_lmn'
output:
dgl
You can try this (or even create a function):
DECLARE #str varchar(250) = 'abc_def_ghk_lmn'
DECLARE #result varchar(250)='';
WHILE(charindex('_',#str)!=0)
BEGIN
DECLARE #position int = charindex('_',#str)
SET #result += substring(#str,#position+1,1)
SET #str = substring(#str,#position+1,len(#str))
END
SELECT #result
You can use a recursive CTE:
IF OBJECT_ID('tempdb..#t') is not null drop table #t
SELECT * into #t from (values (N'abc_def_ghk_lmn'), (N'a_f_k_n'), (null), ('____'), ('asasas'), ('a_sasas'), ('asas_')) T(val);
;WITH CTE AS
(
SELECT
Cast(SUBSTRING(T.val, CHARINDEX('_',T.val,1) + 1, 1) as nvarchar(4000)) FC
,CHARINDEX('_', T.val, 1) CI
,val
,0 [level]
from #t T
where CHARINDEX('_', T.val, 1) > 0
union all
SELECT
Cast(T.FC + SUBSTRING(T.val, CHARINDEX('_',T.val,T.CI+1) + 1, 1) as nvarchar(4000)) FC
,CHARINDEX('_', T.val, T.CI+1) CI
,val
,t.[level] + 1
from CTE T
where CHARINDEX('_',T.val,T.CI+1) > 0
)
, Res AS
(
SELECT
*
,ROW_NUMBER() OVER (Partition by val order by [level] desc) RN
from CTE
)
SELECT * from Res where RN = 1
This uses Jeff Moden's DelimitedSplit8K Function. Firstly because i don't know what version of SQL Server you are using, and secondly, the inbuilt function STRING_SPLIT (available in SQL Server 2016 onwards) doesn't include an Item Number value (thus how does one exclude the first result?):
SELECT (SELECT LEFT(Item, 1)
FROM DelimitedSplit8K ('abc_def_ghk_lmn','_') DS
WHERE DS.ItemNumber > 1
FOR XML PATH(''));
Edit:
Example with a dataset:
WITH VTE AS(
SELECT *
FROM (VALUES ('asdgsad_sdfh_sadfh'),('_ashdf+ashd'),('jsda_sdkhfsdjf_654_asdfkhasd_567465413_kasbgdjkasdj')) V(S))
SELECT (SELECT LEFT(Item, 1)
FROM DelimitedSplit8K (S,'_') DS
WHERE DS.ItemNumber > 1
FOR XML PATH('')) AS FirstCharacters
FROM VTE;
Try this:
DECLARE #String VARCHAR(50)= 'abc_def_ghk_lmn',#Result VARCHAR(10)=''
WHILE CHARINDEX('_',#String)>0
BEGIN
SELECT #Result=#Result + SUBSTRING(#String,CHARINDEX('_',#String)+1,1)
SELECT #String=RIGHT(#String,LEN(#String)- CHARINDEX('_',#String))
END
SELECT #Result FinalResult
OUTPUT:
FinalResult
dgl
Please try this -...Always use SET BASED Approach
SOLUTION
DECLARE #x AS XML=''
DECLARE # AS VARCHAR(1000) = 'abc_def_ghk_lmn_'
SET #x = CAST('<A>'+ REPLACE(#,'_','</A><A>')+ '</A>' AS XML)
;WITH CTE AS
(
SELECT t.value('.', 'VARCHAR(10)') Value FROM #x.nodes('/A') AS x(t)
)
,CTE1 AS
(
SELECT * , ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) rnk FROM CTE
)
,CTE2 AS
(
SELECT SUBSTRING(Value,1,1) v , rnk FROM CTE1
)
SELECT CASE WHEN LEFT(#,1) <> '_' THEN MAX(SUBSTRING(u,2,LEN(u))) ELSE MAX(u) END finalstr from (
SELECT
(
SELECT '' + v
FROM CTE2 a
FOR XML PATH('')
)u
FROM CTE2 )x
OUTPUT
finalstr
---------------
dgl
(1 row affected)
Try this below
DECLARE #str TAble(String varchar(250))
INSERT INTO #str
SELECT 'abc_def_ghk_lmn_opq_rst_uvw_xyz'
SELECT STUFF((SELECT ''+LEFT(String,1) FROM
(
SELECT Split.a.value('.','Varchar(1000)') As String,
ROW_NUMBER()OVER(ORDER BY (SELECT 1)) AS Id FROM
(
SELECT CASt('<S>'+REPLACE(String,'_','</S><S>')+'</S>' AS XML )AS String
FROM #str
)as A
CROSS APPLY String.nodes ('S') AS Split(a)
)dt
WHERE dt.Id <>1
FOR XML PATH ('')),1,0,'') AS ExpectedColumn
Result
ExpectedColumn
--------------
dglorux
Use LEFT to get the left part and INSTR to find underscore and finally get your string:
SELECT LEFT(FIELD_1, CHARINDEX('_', FIELD_1) - 2) AS [ANY_ALIAS]
FROM TABLE_1;
EDIT: Now is MSSQL... ;D

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.