SQL function parsing out text from a column - sql

i have a table with some text i want to parse out and i'm very close to the solution but its not quite there. i have a column called indicatornumerator and i want to parse out similar to below ie i want to each of the values in between the square brackets onto a new row. as you can see from the output below i am getting a repeat for the first value after the minus. this does not happen for those which do not have a minus.
my function is as follows:
alter function fn_breakdown (#string varchar(max))
returns #breakdown table
(
originalstr varchar(max),
breakdownstr varchar(max)
)
as
begin
while charindex('r',#string,1) >0
begin
insert into #breakdown
select #string,
SUBSTRING(#string,CHARINDEX('r',#string,1),CHARINDEX(']',#string,1)-CHARINDEX('r',#string,1))
set #string = right(#string,len(#string)-CHARINDEX(')',#string,1))
end
return
end
a second thing i would like to do is to return those after the minus as a minus value rather eg. -R101 instead of R101 as i need to subtract those values later.
Any help much appreciated
the below should create a temporary table and will show you the output i'm getting. you will see that one of the rows duplicates. i am looking to have one row for each value beginning with 'R' in the indicatornumerator column
create table #temped2
(
indicatornumerator varchar(max)
)
insert into #temped2
select '(SUM([R4]) + SUM([R1010])) - (SUM([R1035]) + SUM([R1034]))'
select * from #temped2
cross apply fn_breakdown(indicatornumerator)

Download a copy of ngrams8k and then:
-- sample data
DECLARE #yourtable TABLE (IndicatorNumerator varchar(1000));
INSERT #yourtable
SELECT 'SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200])' UNION ALL
SELECT 'SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999])';
-- Solution
SELECT
t.IndicatorNumerator,
breakdownstr = substring(t.IndicatorNumerator, ng.position+1, n.d-ng.position-1)
FROM #yourtable t
CROSS APPLY dbo.ngrams8k(t.IndicatorNumerator, 2) ng
CROSS APPLY (VALUES (charindex(']',t.IndicatorNumerator, ng.position+1))) n(d)
WHERE ng.token = '[R';
Returns:
IndicatorNumerator breakdownstr
-------------------------------------------------------- --------------
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200]) R4
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200]) R1010
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200]) R50
SUM([R4]) + SUM([R1010]) - SUM([R50]) + SUM([R200]) R200
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999]) R554
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999]) R210
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999]) R500
SUM([R554]) + SUM([R210]) - SUM([R500]) + SUM([R999]) R999

Please try this code if you are using SQL Server 2016 and avove
;WITH cte_date
AS
(
SELECT indicatornumerator, REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(indicatornumerator,'(',''),')',''),'[',''),']',''),'SUM',''),'- ','-') ParsedData
FROM #temped2
)
SELECT *
FROM cte_date
CROSS APPLY STRING_SPLIT(ParsedData, ' ')
WHERE [VALUE] != '+';
Below script will work older than sql server 2016
CREATE FUNCTION [dbo].[StrParse]
(#delimiter CHAR(1),
#csv NTEXT)
RETURNS #tbl TABLE(Keys NVARCHAR(255))
AS
BEGIN
DECLARE #len INT
SET #len = Datalength(#csv)
IF NOT #len > 0
RETURN
DECLARE #l INT
DECLARE #m INT
SET #l = 0
SET #m = 0
DECLARE #s VARCHAR(255)
DECLARE #slen INT
WHILE #l <= #len
BEGIN
SET #l = #m + 1--current position
SET #m = Charindex(#delimiter,Substring(#csv,#l + 1,255))
IF #m <> 0
SET #m = #m + #l
--insert #tbl(keys) values(#m)
SELECT #slen = CASE
WHEN #m = 0 THEN 255
ELSE #m - #l
END
IF #slen > 0
BEGIN
SET #s = Substring(#csv,#l,#slen)
INSERT INTO #tbl
(Keys)
SELECT #s
END
SELECT #l = CASE
WHEN #m = 0 THEN #len + 1
ELSE #m + 1
END
END
RETURN
END
GO
;WITH cte_date
AS
(
SELECT indicatornumerator, REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(indicatornumerator,'(',''),')',''),'[',''),']',''),'SUM',''),'- ','-'),'+ ','') ParsedData
FROM #temped2
)
SELECT *
FROM cte_date
CROSS APPLY dbo.StrParse(' ', ParsedData)
go

Related

STRING_SPLIT in SQL Server 2012

I have this parameter
#ID varchar = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20'
I want to do something to split the comma-separated values.
The string_split function doesn't work and I get this error:
The STRING_SPLIT function is available only under compatibility level 130
and I try to alter my database and set the compatibility to 130 but I don't have a permission for this change.
Other approach is to use XML Method with CROSS APPLY to split your Comma Separated Data :
SELECT Split.a.value('.', 'NVARCHAR(MAX)') DATA
FROM
(
SELECT CAST('<X>'+REPLACE(#ID, ',', '</X><X>')+'</X>' AS XML) AS String
) AS A
CROSS APPLY String.nodes('/X') AS Split(a);
Result :
DATA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Example :
DECLARE #ID NVARCHAR(300)= '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20';
DECLARE #Marks NVARCHAR(300)= '0,1,2,5,8,9,4,6,7,3,5,2,7,1,9,4,0,2,5,0';
DECLARE #StudentsMark TABLE
(id NVARCHAR(300),
marks NVARCHAR(300)
);
--insert into #StudentsMark
;WITH CTE
AS (
SELECT Split.a.value('.', 'NVARCHAR(MAX)') id,
ROW_NUMBER() OVER(ORDER BY
(
SELECT NULL
)) RN
FROM
(
SELECT CAST('<X>'+REPLACE(#ID, ',', '</X><X>')+'</X>' AS XML) AS String
) AS A
CROSS APPLY String.nodes('/X') AS Split(a)),
CTE1
AS (
SELECT Split.a.value('.', 'NVARCHAR(MAX)') marks,
ROW_NUMBER() OVER(ORDER BY
(
SELECT NULL
)) RN
FROM
(
SELECT CAST('<X>'+REPLACE(#Marks, ',', '</X><X>')+'</X>' AS XML) AS String
) AS A
CROSS APPLY String.nodes('/X') AS Split(a))
INSERT INTO #StudentsMark
SELECT C.id,
C1.marks
FROM CTE C
LEFT JOIN CTE1 C1 ON C1.RN = C.RN;
SELECT *
FROM #StudentsMark;
Inline function based on Yogesh Sharma and Salman A answers:
Create FUNCTION [dbo].[fn_split_string]
(
#string nvarchar(max),
#delimiter nvarchar(max)
)
/*
The same as STRING_SPLIT for compatibility level < 130
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-ver15
*/
RETURNS TABLE AS RETURN
(
SELECT
--ROW_NUMBER ( ) over(order by (select 0)) AS id -- intuitive, but not correect
Split.a.value('let $n := . return count(../*[. << $n]) + 1', 'int') AS id
, Split.a.value('.', 'NVARCHAR(MAX)') AS value
FROM
(
SELECT CAST('<X>'+REPLACE(#string, #delimiter, '</X><X>')+'</X>' AS XML) AS String
) AS a
CROSS APPLY String.nodes('/X') AS Split(a)
)
Example:
DECLARE #ID NVARCHAR(300)= 'abc,d,e,f,g';
select * from fn_split_string(#ID,',')
-- If you need exactly string_split functionality (without id column):
select value from fn_split_string(#ID,',')
Another approach would be to use CHARINDEX and SUBSTRING in a WHILE:
DECLARE #IDs VARCHAR(500);
DECLARE #Number VARCHAR(500);
DECLARE #charSpliter CHAR;
SET #charSpliter = ',';
SET #IDs = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20' + #charSpliter;
WHILE CHARINDEX(#charSpliter, #IDs) > 0
BEGIN
SET #Number = SUBSTRING(#IDs, 0, CHARINDEX(#charSpliter, #IDs));
SET #IDs = SUBSTRING(#IDs, CHARINDEX(#charSpliter, #IDs) + 1, LEN(#IDs));
PRINT #Number;
END;
Alternate function to String_Split for older versions of SQL Server
Create this Function in your Database
Create Function dbo.Test_Split( #string varchar(4000))
Returns
#Result Table (value varchar(100))
As
Begin
declare #len int, #loc int = 1
While #loc <= len(#string)
Begin
Set #len = CHARINDEX(',', #string, #loc) - #loc
If #Len < 0 Set #Len = len(#string)
Insert Into #Result Values (SUBSTRING(#string,#loc,#len))
Set #loc = #loc + #len + 1
End
Return
End
How to Use
Select
*
From
dbo.Test_Split('First,Second,Third,Fourth')
For those looking how to transform multi-line text into rows, here is a code based on the answer:
declare #text varchar(max) = 'line0
line1
line2'
select split.a.value('.', 'nvarchar(max)') data
from
(
select cast('<x>' + replace(#text, char(13) + char(10), '</x><x>') + '</x>' as xml) as string
) as a
cross apply string.nodes('/x') as split(a)
Thank you al3x-m.
i create this function for reused in many time.
CREATE FUNCTION STRING_SPLIT_POLYFILL2016 (
#string NVARCHAR(4000)
,#separator NVARCHAR(4000)
)
RETURNS #T TABLE (ColName VARCHAR(4000))
AS
BEGIN
/*
pitt phunsanit
polyfill of STRING_SPLIT in SQL Server 2016
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-ver15
https://stackoverflow.com/questions/46902892/string-split-in-sql-server-2012
*/
DECLARE #Number VARCHAR(4000);
SET #string = #string + #separator;
WHILE CHARINDEX(#separator, #string) > 0
BEGIN
SET #Number = SUBSTRING(#string, 0, CHARINDEX(#separator, #string));
SET #string = SUBSTRING(#string, CHARINDEX(#separator, #string) + 1, LEN(#string));
INSERT INTO #T (ColName)
VALUES (#Number)
END
RETURN
END
-- DEMO
DECLARE #IDS NVARCHAR(4000)
SET #IDS = 'pitt,phunsanit,01,02,03,4,5,6,7,8,9,10,พิชญ์,พันธุ์สนิท'
SELECT *
FROM STRING_SPLIT_POLYFILL2016(#IDS, ',')
Live demo on dbfiddle
A little variation of #Al3x_M's polyfill, when it is not possible to change the database compatibility level : I use a TABLE variable to store the list of value, for using them later in another query:
DECLARE #IDs VARCHAR(500);
SET #IDs = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,2a0' ;
declare #list TABLE (id int);
DECLARE #Number int, #idx int
DECLARE #charSpliter CHAR;
SET #charSpliter = ','
SET #IDs = #IDs + #charSpliter;
set #idx = 0
WHILE (1 = 1)
BEGIN
set #idx = CHARINDEX(#charSpliter, #IDs)
if (#idx is NULL or #idx <= 0) break;
BEGIN TRY
SET #Number = SUBSTRING(#IDs, 0, #idx)
SET #IDs = SUBSTRING(#IDs, #idx + 1, LEN(#IDs))
insert #list select convert(int, #Number)
END TRY
BEGIN CATCH
break
END CATCH
END
-- #list available for the next query...
select * from #list
Add a another method to split string. It is faster I used. especially to split log string. more information please refer: https://sqlperformance.com/2012/07/t-sql-queries/split-strings
create FUNCTION [dbo].[UFN_STRING_SPLIT]
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(max)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a
CROSS APPLY x.nodes('i') AS y(i)
);
test code:
declare #sql nvarchar(max)
set #sql ='ZJNB015,ZJNB014,ZJNB008,ZJNB005,ZJJX018,ZJJX013,ZJJX011,ZJJX007,ZJHZ092,ZJHZ090,ZJHZ088,ZJHZ086,ZJHZ066,ZJHZ063,ZJHZ061,ZJHZ058,ZJHZ047,ZJHZ009,YNKM156,YNKM155,YNKM153,YNKM152,YNKM151,YNKM150,YNKM148,YNKM147,YNKM146,YNKM144,YNKM143,YNKM142,YNKM141,YNKM133,YNKM132,YNKM130,YNKM128,YNKM127,YNKM125,YNKM124,YNKM098,YNKM097,YNKM093,YNKM092,YNKM085,YNKM079,YNKM059,YNKM057,YNKM025,YNKM019,YNKM017,YNKM015,YNKM013,YNKM012,YNKM011,YNKM009,YNKM008,YNKM007,YNKM006,YNKM005,XJWLMQ047,XJWLMQ038,XJWLMQ022,XJWLMQ014,TJTJ129,TJTJ104,TJTJ090,TJTJ089,TJTJ085,TJTJ084,TJTJ065,TJTJ061,TJTJ058,TJTJ055,TJTJ050,TJTJ038,TJTJ036,TJTJ026,TJTJ024,TJTJ022,TJTJ021,TJTJ019,TJTJ018,TJTJ015,TJTJ009,TJTJ008,TJTJ003,SXYC001,SXXA037,SXXA027,SXXA021,SXXA020,SXXA013,SXXA012,SXXA011,SXXA005,SXXA002,SXTY044,SXTY039,SXTY032,SXTY024,SXTY022,SXTY012,SXTY009,SXTY008,SXDT001,SX006222,SX006183,SX006176,SX006152,SX005976,SX005937,SX005799,SX005668,SX005407,SX000825,SX000403,SX000194,SX000171,SX000130,SX000081,SX000078,SX000045,SX000036,SX000018,SX000003,SNC001,SHSH167,SHSH165,SHSH164,SHSH163,SHSH162,SHSH161,SHSH158,SHSH157,SHSH155,SHSH154,SHSH153,SHSH148,SHSH147,SHSH144,SHSH137,SHSH132,SHSH125,SHSH123,SHSH122,SHSH119,SHSH118,SHSH112,SHSH106,SHSH095,SHSH094,SHSH092,SHSH075,SHSH068,SHSH051,SHSH034,SHSH029,SHSH023,SHSH014,SHSH011,SHSH010,SHSH008,SHSH006,SHSH005,SHSH004,SDWZB006,SDWTA002,SDWTA001,SDWJN022,SDWH003,SDQD020,SDQD008,SDJN016,SDJN008,SDCD064,SDCD062,SDCD059,SCYB007,SCNJ010,SCNC022,SCMY029,SCMY028,SCMY014,SCLZ019,SCLS016,SCGY010,SCDY011,SCDY007,SCCD200,SCCD199,SCCD198,SCCD197,SCCD196,SCCD195,SCCD194,SCCD193,SCCD192,SCCD191,SCCD188,SCCD187,SCCD186,SCCD185,SCCD183,SCCD182,SCCD181,SCCD179,SCCD176,SCCD174,SCCD173,SCCD172,SCCD171,SCCD166,SCCD165,SCCD164,SCCD163,SCCD162,SCCD161,SCCD160,SCCD158,SCCD157,SCCD152,SCCD150,SCCD144,SCCD136,SCCD123,SCCD117,SCCD110,SCCD102,SCCD080,SCCD053,SCCD051,SCCD040,SCCD031,SCCD025,SCCD020,SCCD019,SCCD017,SCCD013,SCCD004,SCCD003,SCCD002,QHXN006,QHXN005,QHXN004,NMHHHT003,NMHHHT002,NMBT001,LNSY034,LNSY017,LNSY010,LNSY006,LNSY002,LNSY001,LNJZ008,LNDL030,LNDL016,LNDL008,LNDL005,LNDL002,LNAS008,LNAS004,JXYC109,JXYC065,JXNC1001,JXNC098,JXNC082,JXNC073,JXNC069,JXNC067,JXNC066,JXNC065,JXNC064,JXNC063,JXNC062,JXNC045,JXNC026,JXNC003,JXJJ063,JXJJ061,JXJJ012,JXGZ110,JXGZ106,JXGZ1006,JXGZ1004,JXGZ085,JXGZ068,JXGZ031,JXGZ015,JXGZ011,JXGZ007,JXFZ101,JSZJ010,JSZJ002,JSYZ082,JSYZ081,JSYZ080,JSYZ076,JSYZ075,JSYZ074,JSYZ069,JSYZ067,JSXZ071,JSXZ070,JSXZ068,JSXZ067,JSXZ066,JSXZ064,JSXZ063,JSXZ058,JSXZ057,JSXZ053,JSXZ052,JSXZ051,JSXZ050,JSXZ049,JSXZ046,JSXZ043,JSXZ025,JSXZ022,JSXZ020,JSXZ012,JSXZ011,JSXZ007,JSWX057,JSWX056,JSWX055,JSWX053,JSWX052,JSWX051,JSWX050,JSWX047,JSWX045,JSWX042,JSWX041,JSWX038,JSWX032,JSWX030,JSWX029,JSWX016,JSWX014,JSSZ062,JSSZ061,JSSZ056,JSSZ054,JSSZ052,JSSZ049,JSSZ034,JSSZ031,JSSZ030,JSSZ026,JSSZ023,JSSZ020,JSSZ004,JSSZ002,JSSQ022,JSNT014,JSNT013,JSNJ32,JSNJ093,JSNJ092,JSNJ089,JSNJ087,JSNJ086,JSNJ085,JSNJ084,JSNJ081,JSNJ079,JSNJ078,JSNJ075,JSNJ074,JSNJ071,JSNJ070,JSNJ069,JSNJ066,JSNJ065,JSNJ064,JSNJ063,JSNJ062,JSNJ061,JSNJ052,JSNJ042,JSNJ028,JSNJ026,JSNJ021,JSNJ017,JSNJ015,JSNJ013,JSNJ009,JSLYG104,JSLYG001,JSKS003,JSKS002,JSHA027,JSHA026,JSHA025,JSHA021,JNDZ2,JLJL001,JLCC045,JLCC033,JLCC024,JLCC016,JLCC010,JLCC003,IN995904,IN994165,IN994017,IN976180,IN974591,IN0510360,IN018611,IN017781,IN0176312,IN0174673,IN016272,IN0157453,IN0153814,IN0152570,IN0139922,IN0139920,IN0136951,IN0136160,IN012803,IN0126336,IN0123703,IN011648,IN0115515,IN0099299,IN0092308,IN007290,IN007253,IN006969,IN0066740,IN005618,IN005452,IN005309,IN0051963,IN005110,IN005109,IN005106,IN0050678,IN004129,IN004113,IN004103,IN0032362,IN0028960,IN0028115,IN0023061,IN002245,IN002214,IN0021930,IN002072,IN002035,IN001925,IN001827,IN0017119,IN001708,IN001620,IN001613,IN001611,IN001598,IN001577,IN001520,IN001454,IN001391,IN001374,IN001371,IN001367,IN001365,IN001360,IN001357,IN001345,IN001340,IN001335,IN001333,IN001300,IN001255,IN001248,IN001247,IN001240,IN001225,IN001211,IN001183,IN001181,IN001175,IN001173,IN001144,IN001096,IN001085,IN001073,IN0010637,IN001008,IN000997,IN000995,IN000984,IN000963,IN000958,IN000955,IN000930,IN000925,IN000885,IN000856,IN000813,IN000811,IN000772,IN000408,IN000334,IN000332,IN000325,IN000314,IN000267,IN000217,IN000148,IN000147,IN000145,IN000144,IN000126,IN000118,IN000117,IN000115,IN000114,IN000111,IN000107,IN000092,IN000086,IN000081,IN000073,IN000057,IN000051,IN000029,IN000026,IN000021,IN000018,IN000013,IN000006,HUNZZ077,HUNZZ062,HUNZZ003,HUNYY058,HUNYY002,HUNXT063,HUNSY072,HUNHY076,HUNHY061,HUNHY049,HUNHY008,HUNHY002,HUNHY001,HUNHH080,HUNCS090,HUNCS086,HUNCS085,HUNCS084,HUNCS082,HUNCS081,HUNCS079,HUNCS078,HUNCS076,HUNCS074,HUNCS069,HUNCS061,HUNCS051,HUNCS050,HUNCS046,HUNCS044,HUNCS043,HUNCS037,HUNCS032,HUNCS031,HUNCS012,HUNCS003,HUNCD059,HNZZ1004,HNZZ070,HNZZ064,HNZZ061,HNZZ060,HNZZ056,HNZZ055,HNZZ054,HNZZ052,HNZZ051,HNZZ049,HNZZ037,HNZZ035,HNZZ012,HNZZ011,HNZZ009,HNZZ008,HNZZ004,HNZZ003,HNXX065,HNXX008,HNXX002,HNNY086,HNNY085,HNNY084,HNNY080,HNLY1008,HNLY1007,HNLY071,HNLY068,HNLY050,HNLH075,HNLH041,HNKF1005,HNKF005,HNKF004,HNAY082,HLJHRB033,HLJHRB030,HLJHRB018,HLJHRB012,HLJHRB006,HBYC105,HBYC010,HBYC008,HBYC001,HBXY027,HBXY026,HBXY025,HBXY022,HBXY018,HBXY015,HBXY009,HBXN010,HBXN009,HBXN005,HBXG021,HBXG020,HBXG019,HBXG016,HBXG007,HBWH219,HBWH218,HBWH217,HBWH214,HBWH213,HBWH212,HBWH207,HBWH206,HBWH205,HBWH203,HBWH202,HBWH193,HBWH190,HBWH188,HBWH187,HBWH183,HBWH181,HBWH176,HBWH173,HBWH168,HBWH166,HBWH164,HBWH163,HBWH162,HBWH158,HBWH154,HBWH151,HBWH142,HBWH139,HBWH138,HBWH133,HBWH131,HBWH128,HBWH124,HBWH121,HBWH116,HBWH112,HBWH111,HBWH105,HBWH102,HBWH099,HBWH098,HBWH086,HBWH084,HBWH080,HBWH077,HBWH059,HBWH045,HBWH039,HBWH033,HBWH028,HBWH027,HBWH025,HBWH023,HBWH022,HBWH019,HBWH012,HBWH008,HBSZ003,HBSY004,HBSY003,HBSY001,HBJZ019,HBJZ018,HBJZ017,HBJZ013,HBJZ004,HBJM005,HBHS032,HBHS031,HBHS029,HBHS026,HBHS025,HBHS020,HBHS018,HBHS016,HBHS015,HBHG008,HBEZ001,HBBD003,GZGY059,GZGY058,GZGY057,GZGY056,GZGY055,GZGY053,GZGY050,GZGY044,GZGY041,GZGY039,GZGY038,GZGY037,GZGY033,GZGY013,GZGY010,GZGY007,GZGY005,GZGY004,GZGY003,GXYL019,GXNN038,GXNN037,GXNN033,GXNN032,GXNN031,GXNN030,GXNN018,GXNN017,GXNN007,GXNN004,GXLZ021,GXLZ020,GXLZ019,GXLZ018,GXLZ017,GXLZ014,GXLZ007,GXLZ006,GXLZ004,GXGL040,GXGL038,GXGL036,GXGL035,GXGL034,GXGL032,GXGL031,GXGL030,GXGL013,GXGL012,GXGL011,GXGL002,GXGG002,GXBH003,GXBH001,GSLZ028,GSLZ025,GSLZ015,GSLZ006,GSLZ005,GSLZ004,GSLZ003,GSLZ002,GDZS018,GDZS017,GDZS016,GDZS014,GDZS001,GDZH008,GDZH007,GDZH001,GDSZ047,GDSZ046,GDSZ045,GDSZ044,GDSZ043,GDSZ042,GDSZ040,GDSZ038,GDSZ037,GDSZ036,GDSZ032,GDSZ017,GDSZ013,GDSZ004,GDSZ002,GDSZ001,GDJY011,GDJY010,GDJY009,GDJM010,GDJM009,GDHZ012,GDHZ011,GDHZ008,GDGZ089,GDGZ088,GDGZ087,GDGZ086,GDGZ085,GDGZ084,GDGZ083,GDGZ082,GDGZ081,GDGZ079,GDGZ077,GDGZ076,GDGZ075,GDGZ074,GDGZ073,GDGZ071,GDGZ070,GDGZ068,GDGZ066,GDGZ064,GDGZ062,GDGZ061,GDGZ047,GDGZ042,GDGZ023,GDGZ021,GDGZ006,GDGZ004,GDFS039,GDFS038,GDFS033,GDFS031,GDFS021,GDFS017,GDFS004,GDFS001,GDDW023,GDDW008,GDDW003,GDDG075,GDDG074,GDDG073,GDDG071,GDDG067,GDDG059,GDDG039,FJZZ029,FJZZ028,FJZZ025,FJZZ001,FJXM064,FJXM063,FJXM062,FJXM022,FJXM016,FJXM010,FJQZ025,FJQZ024,FJQZ023,FJQZ022,FJQZ017,FJQZ012,FJPT004,FJPT003,FJPT001,FJLY001,FJFZ043,FJFZ041,FJFZ040,FJFZ037,FJFZ033,FJFZ022,DW407806,DW400478,DW399077,DW395285,DW381615,DW377180,DW368707,DW364714,DW143916,DW143060,DW137429,DW13694,DW126529,DW121990,DW121108,DW118851,DW106708,DW102873,DW098474,DW097703,DW087154,DW083144,DW078807,DW077430,DW071447,DW069691,DW066354,DW065966,DW059329,DW048326,DW042775,DW037572,DW024946,DW024855,DW021684,DW018021,DW014837,DW014059,DW014057,DW014033,DW013990,DW013982,DW013967,DW013948,DW013913,DW013896,DW013889,DW013874,DW013847,DW013816,DW013798,DW013761,DW013742,DW013740,DW013730,DW013658,DW013601,DW013560,DW013529,DW013522,DW013509,DW013442,DW013438,DW013346,DW013341,DW013327,DW013318,DW013256,DW013245,DW013228,DW013211,DW010285,DW004292,CQCQ142,CQCQ140,CQCQ138,CQCQ137,CQCQ136,CQCQ135,CQCQ134,CQCQ132,CQCQ131,CQCQ125,CQCQ122,CQCQ121,CQCQ117,CQCQ116,CQCQ113,CQCQ110,CQCQ108,CQCQ107,CQCQ106,CQCQ101,CQCQ099,CQCQ097,CQCQ094,CQCQ092,CQCQ086,CQCQ085,CQCQ084,CQCQ083,CQCQ082,CQCQ081,CQCQ080,CQCQ077,CQCQ067,CQCQ061,CQCQ044,CQCQ039,CQCQ029,CQCQ028,CQCQ026,CQCQ022,CQCQ021,CQCQ018,CQCQ006,CQCQ005,CQCQ002,BXJWLMQ1364,BXJWLMQ1300,BXJWLMQ1242,BXJWLMQ1082,BXJWLMQ1042,BXJWLMQ0787,BXJWLMQ0682,BXJWLMQ0545,BXJWLMQ0532,BXJWLMQ0528,BTJTJ1575,BTJTJ1552,BTJTJ1486,BTJTJ1469,BTJTJ1467,BTJTJ1408,BTJTJ1398,BTJTJ1327,BTJTJ1209,BTJTJ1200,BTJTJ1180,BTJTJ1178,BTJTJ1062,BTJTJ0958,BTJTJ0942,BTJTJ0852,BTJTJ0793,BTJTJ0671,BTJTJ0649,BTJTJ0614,BTJTJ0603,BTJTJ0536,BTJTJ0530,BTJTJ0527,BTJTJ0488,BTJTJ0448,BTJTJ0422,BTJTJ0184,BTJTJ0064,BSXYC0643,BSXXY1464,BSXXY1406,BSXXY0813,BSXXY0564,BSXXA1623,BSXXA1617,BSXXA1612,BSXXA1611,BSXXA1610,BSXXA1593,BSXXA1592,BSXXA1587,BSXXA1586,BSXXA1574,BSXXA1573,BSXXA1569,BSXXA1568,BSXXA1567,BSXXA1537,BSXXA1517,BSXXA1516,BSXXA1515,BSXXA1514,BSXXA1513,BSXXA1511,BSXXA1503,BSXXA1496,BSXXA1492,BSXXA1483,BSXXA1450,BSXXA1449,BSXXA1446,BSXXA1442,BSXXA1417,BSXXA1384,BSXXA1367,BSXXA1363,BSXXA1357,BSXXA1356,BSXXA1355,BSXXA1354,BSXXA1320,BSXXA1304,BSXXA1284,BSXXA1277,BSXXA1276,BSXXA1270,BSXXA1268,BSXXA1257,BSXXA1254,BSXXA1253,BSXXA1219,BSXXA1206,BSXXA1203,BSXXA1027,BSXXA1024,BSXXA1021,BSXXA1020,BSXXA1011,BSXXA0981,BSXXA0980,BSXXA0957,BSXXA0924,BSXXA0880,BSXXA0860,BSXXA0846,BSXXA0844,BSXXA0828,BSXXA0817,BSXXA0789,BSXXA0738,BSXXA0404,BSXXA0211,BSXXA0050,BSXWN1325,BSXTY1630,BSXTY1585,BSXTY1584,BSXTY1570,BSXTY1551,BSXTY1505,BSXTY1466,BSXTY1453,BSXTY1303,BSXTY1259,BSXTY1229,BSXTY0796,BSXTY0795,BSXTY0769,BSXTY0768,BSXTY0573,BSXTY0547,BSXTY0067,BSXSZ1402,BSXLF1326,BSXBJ1628,BSDZZ1578,BSDZB1590,BSDZB1572,BSDZB1542,BSDZB1447,BSDZB1298,BSDZB0565,BSDYT1522,BSDYT1199,BSDYT0759,BSDYT0748,BSDYT0718,BSDWH0465,BSDWH0464,BSDWF1039,BSDWF0952,BSDTZ1391,BSDTA1558,BSDTA1530,BSDTA1045,BSDRZ1278,BSDQD1445,BSDQD1444,BSDQD1407,BSDQD1365,BSDQD1280,BSDQD1279,BSDQD1233,BSDQD1018,BSDQD0666,BSDQD0584,BSDLY1543,BSDLY1190,BSDJN1559,BSDJN1509,BSDJN1508,BSDJN1506,BSDJN1421,BSDJN1416,BSDJN1349,BSDJN1236,BSDJN1129,BSDJN0960,BSDJN0954,BSDJN0785,BSDJN0560,BSDJN0469,BSDJN0109,BSDJN0070,BSDHZ0826,BSDDZ1624,BQHXN1615,BQHXN1564,BQHXN1512,BQHXN1405,BQHXN1347,BQHXN1346,BQHXN1138,BQHXN1095,BQHXN0841,BQHXN0825,BQHXN0770,BQHXN0722,BQHXN0540,BQHXN0533,BNXZW0832,BNXYC1563,BNXYC1562,BNXYC1561,BNXYC1510,BNXYC1463,BNXYC1426,BNXYC1404,BNXYC1344,BNXYC1258,BNXYC1216,BNXYC1167,BNXYC1092,BNXYC1084,BNXYC0903,BNXYC0884,BNXYC0831,BNXYC0626,BNXYC0562,BNXYC0432,BNXYC0392,BNXYC0325,BNXWZ0498,BNXWZ0497,BNMHHHT0716,BNMHHHT0566,BNMHHHT0423,BNMHHHT0393,BNMHHHT0266,BNMCF1220,BNMCF0928,BNMBT1385,BNMBT1335,BNMBT0715,BLNTL0875,BLNSY1603,BLNSY1539,BLNSY1491,BLNSY1471,BLNSY1455,BLNSY1334,BLNSY1046,BLNSY0987,BLNSY0949,BLNSY0702,BLNSY0698,BLNSY0574,BLNSY0490,BLNKY0641,BLNJZ1547,BLNJZ1523,BLNJZ1498,BLNJZ1137,BLNJZ1034,BLNJZ0644,BLNDL1535,BLNDL1360,BLNDL1341,BLNDL0945,BLNDL0940,BLNDL0882,BLNDL0726,BLNDL0635,BLNDL0595,BLNDL0419,BLNDL0251,BLNAS1501,BLNAS1379,BJLJL1377,BJLCC1224,BJLCC1187,BJLCC1169,BJLCC1159,BJLCC0976,BJLCC0913,BJLCC0798,BJLCC0743,BJLCC0295,BJBJ305,BJBJ300,BJBJ247,BJBJ245,BJBJ211,BJBJ202,BJBJ119,BJBJ114,BJBJ109,BJBJ090,BJBJ087,BJBJ082,BJBJ067,BJBJ066,BJBJ062,BJBJ057,BJBJ056,BJBJ054,BJBJ049,BJBJ048,BJBJ041,BJBJ038,BJBJ029,BJBJ027,BJBJ025,BJBJ011,BJBJ008,BJBJ007,BJBJ004,BJBJ002,BJBJ001,BHLJSH1548,BHLJMDJ1292,BHLJHEB1597,BHLJHEB1549,BHLJHEB1383,BHLJHEB1372,BHLJHEB1343,BHLJHEB1332,BHLJHEB0935,BHLJHEB0800,BHLJHEB0594,BHLJHEB0582,BHLJHEB0264,BHLJHEB0263,BHBXT0513,BHBSJZ1596,BHBSJZ1348,BHBSJZ1310,BHBSJZ1309,BHBSJZ1302,BHBSJZ1223,BHBSJZ1212,BHBSJZ0919,BHBSJZ0873,BHBSJZ0495,BHBSJZ0329,BHBSJZ0324,BHBQHD1436,BHBQHD0805,BHBQHD0585,BHBQHD0459,BHBHD1249,BHBCD1311,BHBBD0858,BHBBD0520,BHBBD0321,BGSLZ1616,BGSLZ1577,BGSLZ1428,BGSLZ1424,BGSLZ1307,BGSLZ1299,BGSLZ1173,BGSLZ0994,BGSLZ0979,BGSLZ0978,BGSLZ0956,BGSLZ0955,BGSLZ0933,BGSLZ0927,BGSLZ0812,BGSLZ0694,BGSLZ0576,BGSLZ0431,BGSLZ0402,BGSLZ0296,BGSLZ0014,BBSWH20019,BBSSH20007,BBSSH20001,BBSSCCD20015,BBSNSXTY10001,BBSLN20008,BBSLN20005,BBSJSSZ20001,BBSHEN20005,BBSHEB20004,BBSCQCQ20004,BBJBJ520,BBJBJ1621,BBJBJ1618,BBJBJ1583,BBJBJ1579,BBJBJ1556,BBJBJ1555,BBJBJ1554,BBJBJ1546,BBJBJ1545,BBJBJ1544,BBJBJ1528,BBJBJ1527,BBJBJ1520,BBJBJ1519,BBJBJ1494,BBJBJ1489,BBJBJ1487,BBJBJ1484,BBJBJ1482,BBJBJ1479,BBJBJ1478,BBJBJ1433,BBJBJ1432,BBJBJ1418,BBJBJ1397,BBJBJ1396,BBJBJ1386,BBJBJ1368,BBJBJ1338,BBJBJ1336,BBJBJ1329,BBJBJ1317,BBJBJ1316,BBJBJ1315,BBJBJ1265,BBJBJ1264,BBJBJ1255,BBJBJ1238,BBJBJ1191,BBJBJ1171,BBJBJ1145,BBJBJ1116,BBJBJ1093,BBJBJ1071,BBJBJ1054,BBJBJ1044,BBJBJ0985,BBJBJ0853,BBJBJ0838,BBJBJ0821,BBJBJ0802,BBJBJ0665,BBJBJ0638,BBJBJ0637,BBJBJ0611,BBJBJ0558,BBJBJ0557,BBJBJ0556,BBJBJ0552,BBJBJ0525,BBJBJ0482,BBJBJ0450,BBJBJ0006,ANWH026,ANWH024,ANWH023,ANWH022,ANWH020,ANWH019,ANWH011,ANWH006,ANWH004,ANWH003,ANTL008,ANMAS014,ANMAS013,ANMAS005,ANMAS001,ANLA010,ANLA006,ANLA004,ANLA003,ANHF063,ANHF062,ANHF061,ANHF060,ANHF059,ANHF058,ANHF057,ANHF056,ANHF055,ANHF053,ANHF051,ANHF049,ANHF048,ANHF047,ANHF044,ANHF042,ANHF039,ANHF035,ANHF034,ANHF026,ANHF019,ANHF013,ANHF010,ANHF008,ANFY034,ANFY032,ANFY002,AHWH028,AHWH027,AHSZ022,AHSZ009,AHHN022,AHHB100,AHBZ030,AHBB022,AHBB020,AHAQ007'
select * from dbo.STRING_SPLIT(#sql,',')
If your database compatibility level is lower than 130, SQL Server will not be able to find and execute STRING_SPLIT function. You can change a compatibility level of database using the following command:
ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130
Note that compatibility level 120 might be default even in new Azure SQL Databases.
For reference:
Version - Highest Compatibility Level - Lowest Available Level
SQL 2017 - 140 - 100
SQL 2016 - 130 - 100
SQL 2014 - 120 - 100
SQL 2012 - 110 - 90
SQL 2008 - 100 - 80
SQL 2005 - 90 - 80
SQL 2000 - 80 - 80
Also, check your syntax as well like:
SELECT Value FROM STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ');
You Can try this function
CREATE FUNCTION [dbo].[fnSplitString]
(
#string NVARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #output TABLE(splitdata NVARCHAR(MAX)
)
BEGIN
DECLARE #start INT, #end INT
SELECT #start = 1, #end = CHARINDEX(#delimiter, #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(#delimiter, #string, #start)
END
RETURN
END
EXAMPLE
DECLARE #StringArray VARCHAR(max)
Set #StringArray= 'a,b,c,d,f';
select * from dbo.fnSplitString(#StringArray,',')
I made this as a quick and dirty substitute using the table approach so the end user can select which of the sections they want. The original string can be used in a join or the individual row selected for a scalar result. Tested in
Microsoft SQL Server 2012 (SP4-OD) (KB4091266) - 11.0.7469.6 (X64) Feb 28 2018 17:47:20 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.3 (Build 9600: ) (Hypervisor)
SET QUOTED_IDENTIFIER ON;
SET ANSI_NULLS ON;
GO
Create FUNCTION dbo.StringSplit2012
(
#OriginalString VARCHAR(500)
,#Separator VARCHAR(6)
)
RETURNS #Sections TABLE
(
OriginalString VARCHAR(500) NOT NULL
,StringSection VARCHAR(500) NULL
,SectionNumber INT
)
AS
BEGIN
DECLARE #SectionCount INT;
DECLARE #LoopCounter INT = 1;
DECLARE #RemainingString VARCHAR(500);
DECLARE #CurrentSection VARCHAR(500);
SET #SectionCount =
LEN (#OriginalString) - LEN (REPLACE (#OriginalString, #Separator, ''));
IF #SectionCount = 0
BEGIN
INSERT INTO
#Sections
(
OriginalString
,StringSection
,SectionNumber
)
VALUES
(#OriginalString -- OriginalString - varchar(500)
,#OriginalString -- StringSection - varchar(500)
,1 -- SectionNumber - int
);
END;
ELSE
BEGIN
SET #RemainingString = #OriginalString;
DECLARE #SectionStart INT;
DECLARE #SectionLength INT;
WHILE #LoopCounter <= #SectionCount
BEGIN
SET #SectionStart = 1;
SET #SectionLength = CHARINDEX (#Separator, #RemainingString);
SET #CurrentSection = LEFT(#RemainingString, #SectionLength - 1);
INSERT INTO
#Sections
(
OriginalString
,StringSection
,SectionNumber
)
VALUES
(#OriginalString
,#CurrentSection
,#LoopCounter -- SectionNumber - int
);
SET #RemainingString =
RIGHT(#RemainingString, LEN (#RemainingString) - #SectionLength);
SET #LoopCounter = #LoopCounter + 1;
END;
DECLARE #TotalParsedLength INT =
(
SELECT SUM ( LEN (s.StringSection)) FROM #Sections AS s
) + #SectionCount;
SET #CurrentSection =
RIGHT(#RemainingString, LEN (#OriginalString) - #TotalParsedLength);
INSERT INTO
#Sections
(
OriginalString
,StringSection
,SectionNumber
)
VALUES
(#OriginalString
,#CurrentSection
,#LoopCounter -- SectionNumber - int
);
END;
RETURN;
END;
GO
I hope this saves someone some time. I use STRING_SPLIT in the function I created to give me the package name from a job step's command, and it blew up when I moved to my 2012 server. So I wrote my own. (Like ya do!)
Joey Morgan
BI/Integrations Developer III
Aspen Dental Management, Inc
Syracuse, NY

Reverse only numerical parts of string in sql server

With T-SQL, I'm trying to find the easiest way to reverse numbers in string. so for string like Test123Hello have Test321Hello.
[Before] [After]
Test123Hello Test321Hello
Tt143 Hello Tt341 Hello
12Hll 21Hll
Tt123H3451end Tt321H1543end
you can use this function
CREATE FUNCTION [dbo].[fn_ReverseDigit_MA]
(
#Str_IN nVARCHAR(max)
)
RETURNS NVARCHAR(max)
AS
BEGIN
DECLARE #lenstr AS INT =LEN(#Str_IN)
DECLARE #lastdigend AS INT=0
while (#lastdigend<#lenstr)
BEGIN
DECLARE #strPart1 AS NVARCHAR(MAX)=LEFT(#Str_IN,#lastdigend)
declare #lenstrPart1 AS INT=LEN(#strPart1)
DECLARE #strPart2 AS NVARCHAR(MAX)=RIGHT(#Str_IN,#lenstr-#lastdigend)
declare #digidx as int=patindex(N'%[0-9]%' ,#strPart2)+#lenstrPart1
IF(#digidx=#lenstrPart1)
BEGIN
BREAK;
END
DECLARE #strStartdig AS NVARCHAR(MAX) = RIGHT(#Str_IN,#lenstr-#digidx+1)
declare #NDidx as int=patindex(N'%[^0-9]%' ,#strStartdig)+#digidx-1
IF(#NDidx<=#digidx)
BEGIN
SET #NDidx=#lenstr+1
END
DECLARE #strRet AS NVARCHAR(MAX)=LEFT(#Str_IN,#digidx-1) +REVERSE(SUBSTRING(#Str_IN,#digidx,#NDidx-#digidx)) +RIGHT(#Str_IN,#lenstr-#NDidx+1)
SET #Str_IN=#strRet
SET #lastdigend=#NDidx-1
END
return #Str_IN
END
Just make use of PATINDEX for searching, append to the result string part by part:
CREATE FUNCTION [dbo].[fn_ReverseDigits]
(
#Value nvarchar(max)
)
RETURNS NVARCHAR(max)
AS
BEGIN
IF #Value IS NULL
RETURN NULL
DECLARE
#TextIndex int = PATINDEX('%[^0-9]%', #Value),
#NumIndex int = PATINDEX('%[0-9]%', #Value),
#ResultValue nvarchar(max) = ''
WHILE LEN(#ResultValue) < LEN(#Value)
BEGIN
-- Set the index to end of the string if the index is 0
SELECT #TextIndex = CASE WHEN #TextIndex = 0 THEN LEN(#Value) + 1 ELSE LEN(#ResultValue) + #TextIndex END
SELECT #NumIndex = CASE WHEN #NumIndex = 0 THEN LEN(#Value) + 1 ELSE LEN(#ResultValue) + #NumIndex END
IF #NumIndex < #TextIndex
SELECT #ResultValue = #ResultValue + REVERSE(SUBSTRING(#Value, #NumIndex, #TextIndex -#NumIndex))
ELSE
SELECT #ResultValue = #ResultValue + (SUBSTRING(#Value, #TextIndex, #NumIndex - #TextIndex))
-- Update index variables
SELECT
#TextIndex = PATINDEX('%[^0-9]%', SUBSTRING(#Value, LEN(#ResultValue) + 1, LEN(#Value) - LEN(#ResultValue))),
#NumIndex = PATINDEX('%[0-9]%', SUBSTRING(#Value, LEN(#ResultValue) + 1, LEN(#Value) - LEN(#ResultValue)))
END
RETURN #ResultValue
END
Test SQL
declare #Values table (Value varchar(20))
INSERT #Values VALUES
('Test123Hello'),
('Tt143 Hello'),
('12Hll'),
('Tt123H3451end'),
(''),
(NULL)
SELECT Value, dbo.fn_ReverseDigits(Value) ReversedValue FROM #Values
Result
Value ReversedValue
-------------------- --------------------
Test123Hello Test321Hello
Tt143 Hello Tt341 Hello
12Hll 21Hll
Tt123H3451end Tt321H1543end
NULL NULL
hope this help:
declare #s nvarchar(128) ='Test321Hello'
declare #numStart as int, #numEnd as int
select #numStart =patindex('%[0-9]%',#s)
select #numEnd=len(#s)-patindex('%[0-9]%',REVERSE(#s))
select
SUBSTRING(#s,0,#numstart)+
reverse(SUBSTRING(#s,#numstart,#numend-#numstart+2))+
SUBSTRING(#s,#numend+2,len(#s)-#numend)
Use this function it will handle multiple occurrence of numbers too
create FUNCTION [dbo].[GetReverseNumberFromString] (#String VARCHAR(2000))
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #Count INT
DECLARE #IntNumbers VARCHAR(1000)
declare #returnstring varchar(max)=#String;
SET #Count = 0
SET #IntNumbers = ''
WHILE #Count <= LEN(#String)
BEGIN
IF SUBSTRING(#String, #Count, 1) >= '0'
AND SUBSTRING(#String, #Count, 1) <= '9'
BEGIN
SET #IntNumbers = #IntNumbers + SUBSTRING(#String, #Count, 1)
END
IF (
SUBSTRING(#String, #Count + 1, 1) < '0'
OR SUBSTRING(#String, #Count + 1, 1) > '9'
)
AND SUBSTRING(#String, #Count, 1) >= '0'
AND SUBSTRING(#String, #Count, 1) <= '9'
BEGIN
SET #IntNumbers = #IntNumbers + ','
END
SET #Count = #Count + 1
END
declare #RevStrings table (itemz varchar(50))
INSERT INTO #RevStrings(itemz)
select items from dbo.Split(#IntNumbers,',')
select #returnstring = Replace(#returnstring, itemz,REVERSE(itemz))from #RevStrings
RETURN #returnstring
END
your sample string
select [dbo].[GetReverseNumberFromString]('Tt123H3451end')
result
Tt321H1543end
UPDATE :
if you do not have Split function then first create it
i have included it below
create FUNCTION Split
(
#Input NVARCHAR(MAX),
#Character CHAR(1)
)
RETURNS #Output TABLE (
Items NVARCHAR(1000)
)
AS
BEGIN
DECLARE #StartIndex INT, #EndIndex INT
SET #StartIndex = 1
IF SUBSTRING(#Input, LEN(#Input) - 1, LEN(#Input)) <> #Character
BEGIN
SET #Input = #Input + #Character
END
WHILE CHARINDEX(#Character, #Input) > 0
BEGIN
SET #EndIndex = CHARINDEX(#Character, #Input)
INSERT INTO #Output(Items)
SELECT SUBSTRING(#Input, #StartIndex, #EndIndex - 1)
SET #Input = SUBSTRING(#Input, #EndIndex + 1, LEN(#Input))
END
RETURN
END
GO
This is a set based approach:
;WITH Tally (n) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) a(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
), UnpivotCTE AS (
SELECT id, x.c, n, y.isNumber,
n - ROW_NUMBER() OVER (PARTITION BY id, y.isNumber
ORDER BY n) AS grp
FROM mytable
CROSS JOIN Tally
CROSS APPLY (SELECT SUBSTRING(col, n, 1)) AS x(c)
CROSS APPLY (SELECT ISNUMERIC(x.c)) AS y(isNumber)
WHERE n <= LEN(col)
), ToConcatCTE AS (
SELECT id, c, n, isNumber,
grp + MIN(n) OVER (PARTITION BY id, isNumber, grp) AS grpAsc
FROM UnpivotCTE
)
SELECT id, col,
REPLACE(
(SELECT c AS [text()]
FROM ToConcatCTE AS t
WHERE t.id = m.id
ORDER BY id,
grpAsc,
CASE WHEN isNumber = 0 THEN n END,
CASE WHEN isNumber = 1 THEN n END DESC
FOR XML PATH('')), ' ',' ') AS col2
FROM mytable AS m
A tally table is used in order to 'unpivot' all characters of the string. Then ROW_NUMBER is used in order to identify islands of numeric and non-numeric characters. Finally, FOR XML PATH is used to reconstruct the initial string with numerical islands reversed: ORDER BY is used to sort islands of numeric characters in reversed order.
Fiddle Demo here
This would do the specific string you are asking for:
select
substring('Test123Hello',1,4)
+
reverse(substring('Test123Hello',5,3))
+
substring('Test123Hello',8,5)
Judging by the rest of the values it looks like you would need to make templates for any of the alphanumeric patterns you are getting. For example you would apply the above to any values that had the shape:
select * from [B&A] where [before] like '[a-z][a-z][a-z][a-z][0-9][0-9][0-9]
[a-z][a-z][a-z][a-z][a-z]'
In other words, if you put the values (before and after) into a table [B&A] and called the columns 'before' and 'after' then ran this:
select
substring(before,1,4)
+
reverse(substring(before,5,3))
+
substring(before,8,5) as [after]
from [B&A] where [before] like '[a-z][a-z][a-z][a-z][0-9][0-9][0-9][a-z]
[a-z][a-z][a-z][a-z]'
Then it would give you 'Test321Hello'.
However the other 3 rows would not be affected unless you created a similar
'[0-9][a-z]' type template for each alphanumeric shape and applied this to the [B&A] table. You would have to select the results into a temp table or another table.
By applying each template in turn you'd get most of it then you'd have to see how many rows were unaffected and check what the alphanumeric shape is and make more templates. Eventually you have a set of code which, if you ran it would capture all possible combinations.
You could just sit down and design a code in this way which captured all possible combinations of [a-z] and [0-9]. A lot depends on the maximum number of characters you are dealing with.

SQL replace every other comma with a semicolon

I have a bunch of strings that should have been stored as value pairs but were not. Now I need to replace every other comma with a semicolon to make them pairs. Hoping to find a simple way of doing this, but there might not be one.
ex:
-1328.89,6354.22,-1283.94,6242.96,-1172.68,6287.91,-1217.63,6399.18
should be:
-1328.89,6354.22;-1283.94,6242.96;-1172.68,6287.91;-1217.63,6399.18
create function f_tst(#a varchar(100)) -- use right size of field
returns varchar(100) -- make sure you use the right size of field
begin
declare #pos int = charindex(',', #a) + 1
;while 0 < charindex(',', #a, #pos)
select #a = stuff(#a, charindex(',', #a, #pos), 1, ';'),
#pos = charindex(',', #a, charindex(',', #a, #pos + 1)) + 1
return #a
end
go
declare #a varchar(100) = '-1328.89,6354.22,-1283.94,6242.96,-1172.68,6287.91,-1217.63,6399.18'
select dbo.f_tst(#a)
Or in your example
update <table>
set <field> = dbo.f_tst(<field>)
Surely not so simple as you want, but a CHARINDEX/SUBSTRING solution:
Declare #input nvarchar(max) = '-1328.89,6354.22,-1283.94,6242.96,-1172.68,6287.91,-1217.63,6399.18'
Declare #i int = 0, #t int = 0, #isComma bit = 1
Declare #output nvarchar(max) = ''
Select #i = CHARINDEX(',', #input)
While (#i > 0)
Begin
Select #output = #output + SUBSTRING(#input, #t + 1, #i - #t - 1) + CASE #isComma WHEN 1 THEN ',' ELSE ';' END
Select #t = #i
Select #i = CHARINDEX(',', #input, #i + 1), #isComma = 1 - #isComma
End
Select #output = #output + SUBSTRING(#input, #t + 1, 1000)
Select #output
This can be done with a combination of dynamic sql and for xml:
declare #sql nvarchar(max)
set #sql = '-1328.89,6354.22,-1283.94,6242.96,-1172.68,6287.91,-1217.63,6399.18'
set #sql = '
select replace((select cast(value as varchar(50)) +
cast(case row_number() over(order by sort)%2 when 0 then '','' else '';'' end as char(1))
from (select ' + replace(#sql,',',' value,1 sort union all select ') + ',1 sort)q
for xml path(''''))+''||'','',||'','''') YourUpdatedValue'
exec(#sql)
This can be done in a single query:
DECLARE #t TABLE (id int, col varchar(max))
INSERT #t VALUES
(1,'-1328.89,6354.22,-1283.94,6242.96,-1172.68,6287.91,-1217.63,6399.18'),
(2,'-4534.89,454.22,-1123.94,2932.96,-1872.68,327.91,-417.63,635.18')
;WITH t AS (
SELECT id, i % 2 x, i / 2 y, val
FROM #t
CROSS APPLY (SELECT CAST('<a>'+REPLACE(col,',','</a><a>')+'</a>' AS xml) xml1 ) t1
CROSS APPLY (
SELECT
n.value('for $i in . return count(../*[. << $i])', 'int') i,
n.value('.','varchar(max)') AS val
FROM xml1.nodes('a') x(n)
) t2
)
SELECT id, y, [0]+','+[1] col
FROM t
PIVOT(MAX([val]) FOR x IN ([0],[1])) t3
ORDER BY id, y
id y val
----------------------------
1 0 -1328.89,6354.22
1 1 -1283.94,6242.96
1 2 -1172.68,6287.91
1 3 -1217.63,6399.18
2 0 -4534.89,454.22
2 1 -1123.94,2932.96
2 2 -1872.68,327.91
2 3 -417.63,635.18

Retrieve multiple pieces of data from a single SQL Server variable

I have two variables like:
#FieldName
#values
Those two variables hold values like:
#FieldName - contains [a],[b],[c],[d]
#values - contains 5,6,7,8
Now I need to retrieve the data of column 'b' & 'd' only.
How can we get b=6 & d=8?
Thanks in advance.
well I hate to do such a things on SQL Server, but
declare #FieldName nvarchar(max) = '[a],[b],[c],[d]'
declare #values nvarchar(max) = '5,6,7,8'
declare #i int, #j int, #break int
declare #a nvarchar(max), #b nvarchar(max), #result nvarchar(max)
select #break = 0
while #break = 0
begin
select #i = charindex(',', #FieldName), #j = charindex(',', #values)
if #i > 0 and #j > 0
begin
select #a = left(#FieldName, #i - 1), #b = left(#values, #j - 1)
select #FieldName = right(#FieldName, len(#FieldName) - #i), #values = right(#values, len(#values) - #j)
end
else
begin
select #a = #FieldName, #b = #values, #break = 1
end
if #a in ('[b]', '[d]')
select #result = isnull(#result + ' & ', '') + #a + '=' + #b
end
select #result
You can also put all this list into temporary/variable table and do join.
select *
from
(
select T.<yourcolumn>, row_number() over (order by T.<yourcolumn>) as rownum
from <temptable1> as T
) as F
inner join
(
select T.<yourcolumn>, row_number() over (order by T.<yourcolumn>) as rownum
from <temptable2> as T
) as V on V.rownum = F.rownum
Or, even better, you can pass parameters into sp in xml form and not in distinct lists
Try this :
Using XML i'm are trying to spilt the values and storing the result in a table variable
DECLARE #FieldName VARCHAR(MAX),
#values varchar(max)
SET #FieldName = 'a,b,c,d';
SET #values = '5,6,7,8'
SET #FieldName = #FieldName + ',';
SET #values = #values + ',';
DECLARE #X XML
SET #X = CAST('<Item>' + REPLACE(#FieldName, ',', '</Item><Item>') + '</Item>' AS XML)
Declare #X1 XML
Set #X1=CAST('<Position>' + REPLACE(#values, ',', '</Position><Position>') + '</Position>' AS XML)
Declare #FieldSample table
(
FieldName char(1),
rowNum int
)
Declare #valueSample table
(position int,
rowNum int)
Insert into #FieldSample(rowNum,FieldName)
Select * from (
SELECT row_number() over (order by (select 0)) as rowNum, t.value('.', 'char(1)') as field
FROM #x.nodes('/Item') as x(t)
) as a
where a.field !=''
Insert into #valueSample(rowNum,position)
Select * from (
Select row_number() over (order by (select 0)) as rowNum, k.value('.', 'int') as position
from #X1.nodes('/Position') as x1(k)
) as b
where b.position !=0
Basically the last logic you can change it based on how you intend to get the data
Select a.FieldName,b.position from #FieldSample as a
inner join #valueSample as b
on a.rowNum=b.rowNum
where b.position = 6 or b.position =8

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)