split text in stored procedure - sql-server

How to split text in stored procedure.
CREATE PROCEDURE
(
#ArrayList nvarchar(1000)
)
BEGIN
--I want to split #ArrayList. That is contains string. ex '1,2,3,4,5,6...'
END

declare #ArrayList nvarchar(1000) = '1,2,3,4,5,6'
declare #XMLList xml
set #XMLList = cast('<I>'+replace(#ArrayList, ',', '</I><I>')+'</I>' as xml)
select
I.value('.', 'int') as Value
from #XMLList.nodes('I') as I(I)

Use should use XML PATH method as below :
SELECT STUFF(
(SELECT TOP 10 ',' + STOCKNO FROM ItemMaster FOR XML PATH('')), 1, 1, ''
) as Data
Result:
Data
150200006,150200010,150200014,150200018,150200021,150200025,150400078,150400082,150200005,150200009

Related

Prepare SUM function for the given dynamic string

Given string:
Note: The following comma separted string is dynamic which comes with any combination.
DECLARE #Str varchar(max) = '[A-B],[B-C],[C-D],[D-E]'
Expected Result:
SUM([A-B]) AS [A-B],SUM([B-C]) AS [B-C],SUM([C-D]) AS [C-D],SUM([D-E]) AS [D-E]
My try:
SELECT 'SUM('+REPLACE(#Str,',','),SUM(')+')'
Output:
SUM([A-B]),SUM([B-C]),SUM([C-D]),SUM([D-E])
Try this
DECLARE #Str AS TABLE ([Str] varchar(max) )
INSERT INTO #Str
SELECT '[A-B],[B-C],[C-D],[D-E]'
;WITH CTE
AS
(
SELECT 'SUM( '+Split.a.value('.','nvarchar(100)')+' ) AS 'AS [Str],Split.a.value('.','nvarchar(100)') AS [Str1]
FROM
(
SELECT CAST('<S>'+(REPLACE([Str],',','</S><S>')+'</S>') AS XML ) AS [Str]
FROM #Str
)AS A
CROSS APPLY [Str].nodes('S') AS Split(a)
)
SELECT STUFF((SELECT DISTINCT ', '+ CONCAT([Str], [Str1])
FROM CTE
FOR XML PATH ('')),1,1,'') AS ExpectedResult
Result
ExpectedResult
-------------------
SUM( [A-B] ) AS [A-B], SUM( [B-C] ) AS [B-C], SUM( [C-D] ) AS [C-D], SUM( [D-E] ) AS [D-E]
Being SQL Server 2008 you would first need to create an SplitString function (it's already included in SQL Server 2016 and forward), like this one :
T-SQL split string
Then you can calculate your clauses :
select 'sum(' + Name + ', as ' + Name
from SplitString(#Str)
And finally you only need to concatenate all those rows, for example adding for xml path('')
select 'sum(' + Name + ', as ' + Name + ','
from SplitString(#Str)
for xml path('')
Simple way to achieve your task
Declare #str varchar(max) = '[A-B],[B-C],[C-D],[D-E]'
, #Main varchar(max)=''
select #Main += ',sum('+a+')'
from (select distinct value as a from STRING_SPLIT(#str , ',')) as Splt
set #Main= stuff(#Main ,1,1,'')
print #Main
Result : sum([A-B]),sum([B-C]),sum([C-D]),sum([D-E])

how to remove duplicates from a comma seperated string in sql server

how to remove duplicate values from the comma seperated string in sql server. Without using functions
Declare #data varchar(max) = '34.22,768.55,34.22,123.34,12,999.0,999.0'
My expected result should be
34.22,768.55,123.34,12,999.0
i tried this query but it doesn't remove duplicates from the variable.
Declare #data varchar(max) = '34.22,768.55,34.22,123.34,12,999.0,999.0'
set #data= (select '' + cast(cast('<d>'+replace(#data, ', ',',</d><d>')+'</d>' as xml).query('distinct-values(/d)') as varchar(max)) +'')
Please try this -
DECLARE #x AS XML=''
Declare #finalstring varchar(max) = ''
DECLARE #Param AS VARCHAR(100) = '34.22,768.55,34.22,123.34,12,999.0,999.0'
SET #x = CAST('<A>'+ REPLACE(#Param,',','</A><A>')+ '</A>' AS XML)
select #finalstring = #finalstring + value + ',' from (
SELECT t.value('.', 'VARCHAR(10)') Value FROM #x.nodes('/A') AS x(t))p
GROUP BY value
PRINT SUBSTRING(#finalstring,0,LEN(#finalstring))
OUTPUT
12,123.34,34.22,768.55,999.0
For sql 2016+
Declare #data varchar(max) = '34.22,768.55,34.22,123.34,12,999.0,999.0'
Declare #finalstring varchar(max) = ''
select #finalstring = #finalstring + value + ',' from string_split(#data,',')
GROUP BY value
PRINT SUBSTRING(#finalstring,0,LEN(#finalstring))
OUTPUT
12,123.34,34.22,768.55,999.0
Try this
Declare #data varchar(max) = '34.22,768.55,34.22,123.34,12,999.0,999.0'
SELECT STUFF(
(
SELECT DISTINCT ',' + UniqNum FROM
(
SELECT CAST('<d>'+replace(#data, ',','</d><d>')+'</d>' AS XML) AS numberXml
) as t1
CROSS APPLY
(
SELECT my_Data.D.value('.','varchar(50)') as UniqNum
FROM t1.numberXml.nodes('d') as my_Data(D)
) t2
FOR XML PATH('')
), 1, 1, '')
Result
UniqNumber
---------------------------
12,123.34,34.22,768.55,999.0
Try This
Declare #data varchar(max) = '34.22,768.55,34.22,123.34,12,999.0,999.0'
;WITH CTE
AS
(
SELECT
MyStr = SUBSTRING(#data,CHARINDEX(',',#Data)+1,LEN(#data)),
Val = SUBSTRING(#data,1,CHARINDEX(',',#data)-1)
UNION ALL
SELECT
MyStr = CASE WHEN CHARINDEX(',',MyStr)>0
THEN SUBSTRING(MyStr,CHARINDEX(',',MyStr)+1,LEN(MyStr))
ELSE NULL END,
Val = CASE WHEN CHARINDEX(',',MyStr)>0
THEN SUBSTRING(MyStr,1,CHARINDEX(',',MyStr)-1)
ELSE MyStr END
FROM CTE
WHERE ISNULL(REPLACE(MyStr,',',''),'')<>''
)
SELECT
Val = SUBSTRING(List,1,LEN(List)-1)
FROM
(
SELECT
DISTINCT Val+','
FROM CTE
WHERE ISNULL(MyStr ,'')<>''
FOR XML PATH('')
)Q(List)
My Result
12,123.34,34.22,768.55,999.0
Just an another simple way of doing it.
Declare #data Nvarchar(max) = N'34.22,768.55,34.22,123.34,12,999.0,999.0'
, #data2 Nvarchar(max)='';
SELECT #data = N'SELECT #DATA_DIST= #DATA_DIST+VAL+'',''
FROM (SELECT '''+replace(#data,',',''' AS VAL UNION SELECT ''')+''')A';
EXECUTE sp_executesql #data,N'#DATA_DIST varchar(MAX) OUTPUT',#DATA_DIST=#data2 OUTPUT;
SELECT LEFT(#data2,LEN(#data2)-1);
Result:
12,123.34,34.22,768.55,999.0

Getting values of comma separated fields in SQL Server

I have comma separated column which represents the ids of cities like:
ID | Name
1 | 1,2,3
2 | 2,3,4
I want to make query to get name of the this value field. There is City Table which has two columns: id and name of cities
EXPECTED OUTPUT
ID | VALUES
1 | mumbai,delhi,pune
2 | delhi,pune,chennai
I can make a query if there is only one id in a column like:
select data.id,city.name from data,city where data.values=city.cityid
but I am not getting how to retrieve the data if there are multiple comma-separated values in one field.
The easy way is to convert CSV values to rows for each Id, join that with CITY table and convert back to CSV values. I have written the logic inside the query.
;WITH CTE1 AS
(
-- Convert CSV to rows
SELECT Id,LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'NAME'
FROM
(
-- To change ',' to any other delimeter, just change ',' before '</M><M>' to your desired one
SELECT Id,CAST ('<M>' + REPLACE(Name, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM #TEMP
) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)
)
,CTE2 AS
(
-- Now join the values in rows with Id in CITY table
SELECT T.ID,T.NAME,C.CITYNAME
FROM CTE1 T
JOIN #CITY C ON T.NAME=C.ID
)
-- Now convert back to CSV format
SELECT DISTINCT ID,
SUBSTRING(
(SELECT ', ' + CITYNAME
FROM CTE2 I
WHERE I.Id=O.Id
FOR XML PATH('')),2,200000) [VALUES]
FROM CTE2 O
Click here to view result
to do this please do following sections:
1-Create Function to get table of comma separate value in each row
CREATE FUNCTION [dbo].[fn_Split](
#ForigenKey INT,
#String NVARCHAR (4000),
#Delimiter NVARCHAR(10)
)
RETURNS #ValueTable TABLE ([ID] INT IDENTITY NOT NULL,FID int null,[Value] NVARCHAR(4000))
BEGIN
DECLARE #NextString NVARCHAR(4000)
DECLARE #Pos INT
DECLARE #NextPos INT
DECLARE #CommaCheck NVARCHAR(1)
--Initialize
SET #NextString = ''
SET #CommaCheck = RIGHT(#String,1)
--Check for trailing Comma, if not exists, INSERT
--if (#CommaCheck <> #Delimiter )
SET #String = #String + #Delimiter
--Get position of first Comma
SET #Pos = CHARINDEX(#Delimiter,#String)
SET #NextPos = LEN(#Delimiter)
--Loop while there is still a comma in the String of levels
WHILE (#pos <> 0)
BEGIN
SET #NextString = SUBSTRING(#String, 1, #Pos - 1)
INSERT INTO #ValueTable ( FID,[Value]) VALUES (#ForigenKey ,#NextString)
SET #String = SUBSTRING(#String,#pos + LEN(#Delimiter),LEN(#String))
SET #NextPos = #Pos
SET #pos = CHARINDEX(#Delimiter,#String)
END
RETURN
END
GO
2- create Concat Aggregate with the folwing link
Concat Aggregate
3- you can get your data with below select
DECLARE #ID INT,#Name NVARCHAR(4000)
DECLARE #ValueTable table ([ID] int NOT NULL,[Value] INT)
DECLARE mycur CURSOR FOR
SELECT TOP(1000) ID,Name FROM TableA
OPEN mycur
FETCH NEXT FROM mycur INTO #ID,#Name
WHILE(##FETCH_STATUS=0)
BEGIN
INSERT INTO #ValueTable
( ID, Value )
SELECT #ID,Value FROM dbo.fn_Split(#Name,',')
FETCH NEXT FROM mycur INTO #ID,#Name
END
CLOSE mycur
DEALLOCATE mycur
SELECT * FROM #ValueTable
SELECT ID,dbo.ConcatAggregate(CityName) FROM #ValueTable
inner join city on value=cityid GROUP BY ID

Convert table to text in result of a query

Result of a query is table,is it possible to write a query that convert this result to a text (for example imagine that result is a table with 4 rows with value 1 to 4 and convert it to 1,2,3,4)
Yes, you can do that using FOR XML PATH(''). For example:
create table test(col varchar(10))
insert into test values ('1'),('2'),('3'),('4')
select STUFF( (select ',' + col
from test
FOR XML PATH('')), 1, 1, '')
Try the below query
declare #Var varchar(1000);
set #var = ''
select #Var = #var + CONVERT(varchar, Column1) + ','
from Table1
select #var
Try this
DECLARE #result varchar(1000)
SET #result = ''
SELECT #result = #result + StudentId + ',' FROM Student WHERE condition = xyz
select substring(#result, 1, len(#result) -1 --trim extra "," at end
Op like
1,2,3,4,..........
Happy Coding

Parsing XML into a SQL table WITHOUT predefining structure. Possible?

So using the code below... can I parse #xml_data into a table structure without predefining the structure?
DECLARE #receiveTable TABLE(xml_data XML) DECLARE #xml_data XML
DECLARE #strSQL NVARCHAR(2000)
SET #strSQL = 'SELECT * INTO #tmp1 FROM sysobjects;
DECLARE #tbl TABLE(xml_data xml);
DECLARE #xml xml;
Set #xml = (Select * from #tmp1 FOR XML AUTO);
INSERT INTO #tbl(xml_data) SELECT #xml;
SELECT * FROM #tbl'
INSERT INTO #receiveTable EXEC (#strSQL)
SET #xml_data = (SELECT * FROM #receiveTable)
SELECT #xml_data
As in your #xml_data, if /element[1] has the same number of attributes as /element[n] and they're in the same order ltr, you can.
It's not pretty, but you can:
declare #tbl_xml xml
set #tbl_xml = (
select #xml_data.query('
<table>
{for $elem in /descendant::node()[local-name() != ""]
return <row name="{local-name($elem)}">
{for $attr in $elem/#*
return <col name="{local-name($attr)}" value="{$attr}" />}
</row>}
</table>'
)
)
declare #sql_def_tbl varchar(max)
select #sql_def_tbl =
coalesce(#sql_def_tbl,'')
+'declare #tbl table ('+substring(csv,1,len(csv)-1)+') '
from (
select (
select ''+col.value('#name','varchar(max)')+' varchar(max),'
from row.nodes('col') r(col) for xml path('')
) csv from #tbl_xml.nodes('//row[1]') n(row)
) x
declare #sql_ins_rows varchar(max)
select #sql_ins_rows =
coalesce(#sql_ins_rows,'')
+'insert #tbl values ('+substring(colcsv,1,len(colcsv)-1)+') '
from (
select (
select ''''+col.value('#value','varchar(max)')+''','
from row.nodes('col') r(col) for xml path('')
) colcsv from #tbl_xml.nodes('//row') t(row)
) x
exec (#sql_def_tbl + #sql_ins_rows + 'select * from #tbl')

Resources