Getting values of comma separated fields in SQL Server - 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

Related

Add columns dynamically and Later Parse values in the respective columns

I have an SP which accepts the Inputtable as parameter, My Inputtable is as shown in the code
`create table inputTable ( id int,ItemQty varchar(100))
insert into inputTable(id, ItemQty) values(1,'a,b,c')
insert into inputTable(id, ItemQty) values(2,'x,y')
insert into inputTable(id, ItemQty) values(3,'l,m,n,o,p')
insert into inputTable(id, ItemQty) values(4,'a,b')
insert into inputTable(id, ItemQty) values(5,'m')`
and SP i have written is like below
`ALTER PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
-----
declare #maxcount as int
set #maxcount='select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename
exec('select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename)
print #maxcount
exec #maxcount
print #maxcount
declare #var varchar(100)
IF EXISTS(SELECT * FROM sys.columns WHERE object_id = Object_id(#tablename))
set #var='alter table '+ #tablename +' ADD column QTY1'
exec(#var)
select * from #tablename
select max(len(ItemQty))-max(len(replace(ItemQty, ',', ''))-1) from inputtable
END`
My table is :
step 1 ) I want to add the columns dynamically to inputtable like QTY1,QTY2,QTY3,QTY4,QTY5 because maximum count of ItemQty column is 5, by considering comma as delimiter as shown in figure1
**step 2) ** Parse values in the respective columns(by considering the delimiter comma (,).as shown in figure2
Later SP: I got till here, But Not getting the second step, that is update Parse values in the respective columns.
ALTER PROCEDURE dynamic_tbl (#tablename varchar(50))
AS
BEGIN
DECLARE #ColumnCount int
DECLARE #rowcount TABLE (Value int);
INSERT INTO #rowcount
EXEC('select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename);
SELECT #ColumnCount = Value FROM #rowcount;
Declare #ColumnName nvarchar(10)='qty_'
Declare #count int =0
IF(#ColumnCount>0)
BEGIN
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'dyn_tbl'))
BEGIN
DROP TABLE dyn_tbl
END
select * into dyn_tbl from inputtable
SET #count=#count +1;
WHile(#ColumnCount>=#count)
BEGIN
SET #ColumnName='qty_'+CONVERT(varchar(2),#count)
EXEC ('ALTER TABLE dyn_tbl ADD ['+#ColumnName +'] varchar(20)')
declare #myvar as varchar(max)
set #myvar='update '+#tablename+' set '+#ColumnName +' =itemQty'
--exec dynamic_tbl 'dyn_tbl'
--select * from dyn_tbl
--CAST('<A>'+REPLACE(ITEMQTY, ',', '</A><A>')+'</A>' AS XML)
print #myvar
exec(#myvar)
SET #count=#count +1;
END
END
----
END
Procedure to alter given table dynamically based on column length as you have asked
Alter PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
drop table ##temp
declare #query1 varchar(max)
exec ( '
create table ##temp (id int identity,columnsl varchar(100))
declare #maxcount as int
set #maxcount = (select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename+')
declare #count int = 1
while (#count <= #maxcount)
begin
declare #colvar nvarchar(100)= ''QTY''
set #colvar = concat(#colvar,#count)
set #count = #count + 1
insert into ##temp select #colvar
end
')
declare #tempstart int = 1
declare #templast int = (select count(*) from ##temp)
declare #updatecol varchar(100) = ''
while (#tempstart <= #templast)
Begin
set #updatecol = (select columnsl from ##temp where id = #tempstart)
exec ('alter table '+#tablename+' Add '+#updatecol+' varchar(100) ')
set #tempstart = #tempstart + 1
end
End
output for inputTable:
id ItemQty QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c NULL NULL NULL NULL NULL
2 x,y NULL NULL NULL NULL NULL
3 l,m,n,o,p NULL NULL NULL NULL NULL
4 a,b NULL NULL NULL NULL NULL
5 m NULL NULL NULL NULL NULL
may not be the best way but works.
edit
Altered above procedure to perform both actions, Please use below procedure
Alter PROCEDURE [dbo].[Column_Dynamics] (#tablename varchar(50))
AS
BEGIN
-- declare #tablename varchar(100) = 'inputTable'
drop table #temp if object_id('temp..#temp') is not null drop table #temp
declare #query1 varchar(max)
create table #temp (id int identity,columnsl varchar(100))
exec ( '
declare #maxcount as int
set #maxcount = (select MAX(len(ITEMQTY) - len(replace(ITEMQTY, '','', '''')) +1) from '+#tablename+')
declare #count int = 1
while (#count <= #maxcount)
begin
declare #colvar nvarchar(100)= ''QTY''
set #colvar = concat(#colvar,#count)
set #count = #count + 1
insert into #temp
select #colvar
end
')
declare #tempstart int = 1
declare #templast int = (select count(*) from #temp)
declare #updatecol varchar(100) = ''
declare #itemqty varchar(100)
while (#tempstart <= #templast)
Begin
set #updatecol = (select columnsl from #temp where id = #tempstart)
exec ('alter table '+#tablename+' Add '+#updatecol+' varchar(100) ')
set #tempstart = #tempstart + 1
end
declare #sysvar table (id int identity,cols varchar(100))
insert into #sysvar select sys.columns.name AS ColumnName FROM sys.columns JOIN sys.tables ON sys.columns.object_id = sys.tables.object_id WHERE sys.tables.name = 'inputTable'
declare #finvar table (id int identity,cols varchar(100))
insert into #finvar select cols from #sysvar where id not in (1,2)
declare #cat int = 1 declare #dog int = (select max(id) from inputTable)
while (#cat <= #dog)
begin
drop table #tab2
if object_id('temp..#tab2') is not null drop table #tab2
create table #tab2 (id int identity,fnvalues varchar(100))
set #itemqty = (select itemqty from inputTable where id = #cat)
insert into #tab2 select item from [dbo].[fnSplit](#itemQty,',')
declare #cn int = 1
declare #max int = (select max(id) from #tab2)
declare #sql nvarchar (1000);
while (#cn <= #max)
begin
declare #upcol varchar(100) = (select fnvalues from #tab2 where id = #cn)
declare #plscol varchar(100) = (select cols from #finvar where id = #cn)
set #sql = N'update '+#tablename+' set ' + #plscol + '= '''+#upcol+''' where id = '''+cast(#cat as varchar(10))+''' ';
select #sql
exec sp_executesql #sql;
set #cn = #cn + 1
end
set #cat = #cat + 1
End
End
output:
id ItemQty QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c a b c NULL NULL
2 x,y x y NULL NULL NULL
3 l,m,n,o,p l m n o p
4 a,b a b NULL NULL NULL
5 m m NULL NULL NULL NULL
did not optimize the query but works fine.
However, if you have maximum Qty's are known which are in comma separated format then you could use xml node method to separate them into columns.QTY1...QTY5
SELECT DISTINCT ID, ITEMQTY,
a.value('/A[1]', 'VARCHAR(MAX)') as QTY1,
a.value('/A[2]', 'VARCHAR(MAX)') as QTY2,
a.value('/A[3]', 'VARCHAR(MAX)') as QTY3,
a.value('/A[4]', 'VARCHAR(MAX)') as QTY4,
a.value('/A[5]', 'VARCHAR(MAX)') as QTY5
FROM
(
SELECT ID, ITEMQTY,
CAST('<A>'+REPLACE(ITEMQTY, ',', '</A><A>')+'</A>' AS XML) AS ITEMQTY1
FROM inputTable
) A
CROSS APPLY ITEMQTY1.nodes('/A') AS split(a);
Result :
ID ITEMQTY QTY1 QTY2 QTY3 QTY4 QTY5
1 a,b,c a b c NULL NULL
2 x,y x y NULL NULL NULL
3 l,m,n,o,p l m n o p
4 a,b a b NULL NULL NULL
5 m m NULL NULL NULL NULL
Later, you could replace null by using coalesce() or isnull() function with ''
Use This
First Create a function
CREATE FUNCTION [dbo].[fn_split](
#str VARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #returnTable TABLE (idx INT PRIMARY KEY IDENTITY, item VARCHAR(8000))
AS
BEGIN
DECLARE #pos INT
SELECT #str = #str + #delimiter
WHILE LEN(#str) > 0
BEGIN
SELECT #pos = CHARINDEX(#delimiter,#str)
IF #pos = 1
INSERT #returnTable (item)
VALUES (NULL)
ELSE
INSERT #returnTable (item)
VALUES (SUBSTRING(#str, 1, #pos-1))
SELECT #str = SUBSTRING(#str, #pos+1, LEN(#str)-#pos)
END
RETURN
END
GO
and use function like this
Declare #test TABLE (
ID VARCHAR(200),
Data VARCHAR(200)
)
insert into #test
(ID, Data)
Values
(1,'a,b,c')
insert into #test
(ID, Data )
values(2,'x,y')
insert into #test
(ID, Data )
values(3,'l,m,n,o,p')
insert into #test
(ID, Data )
values(4,'a,b')
insert into #test
(ID, Data )
values(5,'m')
select ID,data AS ItemQty,
ISNULL((select item from fn_split(Data,',') where idx in (1)),'') as QTY1 ,
ISNULL((select item from fn_split(Data,',') where idx in (2)),'') as QTY2,
ISNULL((select item from fn_split(Data,',') where idx in (3)),'') as QTY3,
ISNULL((select item from fn_split(Data,',') where idx in (4)),'') as QTY5 ,
ISNULL((select item from fn_split(Data,',') where idx in (5)),'') as QTY5
from #test
Output Same as your Image
instead of using
insert into #test
(ID, Data)
Values
(1,'a,b,c')
you can also assgin it like this
insert into #test
(ID, Data)
Values
(Select Column1, Column2 From YourTable)

How to resolve An INSERT EXEC statement cannot be nested in SQL server

I have a sp in which I am returning one single column result. I am trying to store the result into a table type, but I am getting this error:
An INSERT EXEC statement cannot be nested.
I have googled around but didn't find any acceptable solution.
The sp is as follows:-
ALTER PROCEDURE [dbo].[Sp_DemographicFilter_booster]
(
#FilterSelected FilterSelected READONLY,
#CountryCategoryId int=null
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #WhereCondition varchar(500) ;
DECLARE #QueryString Varchar(MAX) ;
DECLARE #QueryString_booster Varchar(MAX) ;
DECLARE #Filter table (FilterColumn Varchar(200),FilterValue Varchar(200))
DECLARE #Result table (SERIAL int)
DECLARE #Result_booster table (SERIAL int)
if( select top 1 FilterColumn FROM #FilterSelected where FilterColumn<>'HISPANIC') is NOT NULL
BEGIN
Insert into #Filter
Select * from #FilterSelected where FilterColumn<>'HISPANIC'
--DECLARE #DemoTbl TABLE (MetricName VARCHAR(100),CatValue VARCHAR(100))
SELECT #WhereCondition= COALESCE( #WhereCondition + ' and ', '')+SubjectList FROM (
SELECT DISTINCT STD.Filtercolumn +' in ('+
ISNULL(STUFF((SELECT ', '+'''' + ssm.Filtervalue+''''
FROM #Filter SSM
INNER JOIN #Filter SUB ON SUB.FilterColumn = SSM.FilterColumn and SUB.FilterColumn=STD.FilterColumn
WHERE sub.FilterValue = ssm.FilterValue
FOR XML PATH('')
), 1, 1, ''), 'Not Assigned Yet')+')' AS SubjectList
FROM #Filter STD)A
print #WhereCondition
--INSERT INTO #DemoTbl
--select SUBSTRING(col1,1, CHARINDEX(':',col1,1)-1) MetricName,SUBSTRING(col1, CHARINDEX(':',col1,1)+1,LEN(Col1)) CatValue
--from dbo.UF_CSVDataToTable(#FilterSelectedSelected)
SET #QueryString='SELECT SERIAL FROM Logical.Demographic D
WHERE '+#WhereCondition+' and CountryCategoryId='+cast(#CountryCategoryId as varchar(10))
PRINT #QueryString
insert into #Result
EXEC(#QueryString)
--select * from #Result
END
IF(select top 1 FilterColumn FROM #FilterSelected where FilterColumn='HISPANIC') IS NOT NULL
BEGIN
Delete from #Filter;
DECLARE #Response varchar(20)=null;
Insert into #Filter
Select * from #FilterSelected where FilterColumn='HISPANIC'
select #Response=FilterValue from #Filter;
DECLARE #VariableID int=null;
select #VariableID=SurrogateKeyCounter from MetaData.Metadata_Screener where DBMetricName='HISPANIC';
SET #QueryString_booster='SELECT SERIAL FROM Logical.Response R
WHERE variableid='+cast(#VariableID as varchar(10))+' and CountryCategoryId='+cast(#CountryCategoryId as varchar(10))
+' and ResponseName='''+#Response+''''
PRINT #QueryString_booster
Insert into #Result_booster
EXEC(#QueryString_booster)
END
DECLARE #Final_Result table (SERIAL int)
insert into #Final_Result
select * from #Result
UNION
select * From #Result_booster
select * from #Final_Result
END
I am calling this procedure like this:
declare #ds FilterSelected
insert into #ds values('Hispanic','yes')
#FilterSelected=#ds,#CountryCategoryId=100
DECLARE #DemoTbl TABLE (Serial INT)
Insert into #DemoTbl
EXEC Sp_DemographicFilter_booster #FilterSelected=#ds,
#CountryCategoryId=100
Call SP Sp_DemographicFilter_booster along with unique ID .
Inside Sp_DemographicFilter_booster SP create global table (##) stored result in global table with same unique ID AS ID field
Now when return to main SP access global table with where condition that unique ID

How to eliminate column with same name using self join?

In this stored procedure, I have to use
SELECT *
FROM #policyData a
LEFT OUTER JOIN ##Temp b ON b.qguid = a.quoteguid
LEFT OUTER JOIN ##Temp c ON c.qguid = a.quoteguid2;
And because of that I have two columns with the same name "QuoteGuid".
Then when I try to add this query in SSRS, I get an error, because I have 2 columns with the same name.
I am not the author of this stored procedure, so I cannot understand is any chance to eliminate or rename column name that causing this.
CREATE PROCEDURE dbo.SP_Catalytic_WindEQRenewalExtract
#pos INT,
#len INT,
#value varchar(8000),
#PriorDays INT,
#PastDays INT,
#LineName varchar(50)
AS
SET NOCOUNT ON;
SELECT #LineName ='wind'
SELECT #PriorDays= -15
SELECT #PastDays = 55
DECLARE #policyData TABLE
(
NamedInsured varchar(1000),
displaystatus varchar(100),
quoteguid uniqueidentifier,
quoteid int,
controlno int,
ExpirationDate datetime,
MonthName nvarchar(25),
ExpiringPremium money,
Underwriter varchar(250),
linename varchar(25),
RenewalSubmissionRecieved varchar(5),
QuotedPremium money,
quoteguid2 uniqueidentifier,
controlno2 int,
displaystatus2 varchar(50),
quotestatuscomment varchar(2500),
quotestatusreasoncomment varchar(2500),
BoundPremium money,
Underwriter2 varchar(500)
)
INSERT INTO #policyData
EXEC ('Catalytic_sp_FetchRenewalPolicy ' + #PriorDays + ',' + #PastDays + ', ' + #LineName + '')
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT ',' + QUOTENAME(c.locationCode)
FROM Catalytic_vw_LocationCodeByLine c WHERE c.linename =#LineName order by c.CompanyName, c.LocationCode
FOR XML PATH('')),1,1,'')
IF OBJECT_ID('tempdb.dbo.##Temp', 'U') IS NOT NULL
DROP TABLE ##Temp;
set #query =
'select * into ##Temp
from
(SELECT QUOTEGUID as qguid, ' + #cols + ' from
(
select QuoteGUID, LocationCode, LineName,LineGUID
--from Catalytic_vw_PolicyLocationCode where quoteguid=''99D60178-C33B-4A3F-9EA7-0001EF31626A''
from Catalytic_vw_PolicyLocationCode
) x
pivot
(
max(locationCode)
for locationCode in (' + #cols + ')
)p)x'
EXEC sp_executesql #query;
set #pos = 0
set #len = 0
WHILE CHARINDEX(',', #cols, #pos+1)>0
BEGIN
set #len = CHARINDEX(',', #cols, #pos+1) - #pos
set #value = SUBSTRING(#cols, #pos, #len)
-- PRINT #value
set #pos = CHARINDEX(',', #cols, #pos+#len) +1
declare #sql nvarchar (1000);
set #sql = N'update ##Temp set ' + #value + '= ''X'' where len(' + #value + ') > 0 ' ;
exec sp_executesql #sql;
END
SELECT *
FROM
#policyData a
LEFT OUTER JOIN ##Temp b on b.qguid = a.quoteguid
/*Because I am using another LEFT JOIN here, I have two columns namem "qguid"*/
LEFT OUTER JOIN ##Temp c on c.qguid = a.quoteguid2;
DROP TABLE ##Temp;
just change where you are trying to make another left join in the last and explicitly mention all column name.
SELECT a.* ,b.*,c.qguid as qguid1
FROM
#policyData a
LEFT OUTER JOIN ##Temp b on b.qguid = a.quoteguid
/*Because I am using another LEFT JOIN here, I have two columns namem "qguid"*/
LEFT OUTER JOIN ##Temp c on c.qguid = a.quoteguid2;
Another way,
declare #CurDate datetime=getdate()
Declare #CurDate1 varchar(8)
select #CurDate1= replace(convert(varchar(8), #CurDate, 112), ':','')
select #CurDate1
SET #cols = STUFF((SELECT ',' + QUOTENAME(c.locationCode) +#CurDate1
FROM Catalytic_vw_LocationCodeByLine c WHERE c.linename =#LineName order by c.CompanyName, c.LocationCode
FOR XML PATH('')),1,1,'')
If I am understanding your question correctly you need to use an existing stored procedure to get data for an SSRS report and you cannot modify the procedure. The problem is the stored procedure returns two columns with the same name and SSRS will not accept that in a dataset.
To get around that call the stored procedure and store its results in a temp table with different column names. Then output the temp table contents. This gives you fill control over the name of the columns. See example below.
CREATE PROCEDURE dbo.sp_Test
AS
BEGIN
SELECT
1 AS 'Test1',
2 AS 'Test2',
3 AS 'Test3',
3 AS 'Test3'
END
CREATE TABLE #Test
(
Test1 int,
Test2 int,
Test3 int,
Test4 int
)
INSERT INTO #Test
EXEC dbo.sp_Test
SELECT * FROM #Test
DROP TABLE #Test

Comma separted string into columns using SQL Server 2008 R2

I want to insert the bulk values into the table by using stored procedure.
Here is the following table called m1 with two fields:
create table m1
(
cola varchar(50),
colb varchar(50)
);
Procedure m1_test to insert the values into the table:
create procedure m1_test
#stringCola varchar(max),
#stringColb varchar(max)
AS
INSERT INTO m1 values(#stringCola,#stringColb);
GO
The above procedure is fine for inserting single values as shown below:
---EXECUTE SP
EXECUTE m1_test #stringCola = 'A1',#stringColb = 'Z1';
But If I want to insert the more values at a time in single string like shown below:
---EXECUTE SP
EXECUTE m1_test #stringCola = 'A1,A2,A3',#stringColb = 'Z1,Z2,Z3';
The output should be:
cola colb
------------
A1 Z1
A2 Z2
A3 Z3
First you need to create a table valued function which will return the comma separated values in the form of a table.
Implement the below code for the function, which I found here, with a slight modification to return an identity column based on which you will later do a JOIN to get a tuple of the 1st value for column A and the first value for column B (A1, Z1) and so on the 2nd, 3rd etc. :
CREATE FUNCTION Split (#InputString VARCHAR(8000), #Delimiter VARCHAR(50))
RETURNS #Items TABLE (ID INTEGER IDENTITY(1,1), Item VARCHAR(8000))
AS
BEGIN
IF #Delimiter = ' '
BEGIN
SET #Delimiter = ','
SET #InputString = REPLACE(#InputString, ' ', #Delimiter)
END
IF (#Delimiter IS NULL OR #Delimiter = '')
SET #Delimiter = ','
--INSERT INTO #Items VALUES (#Delimiter) -- Diagnostic
--INSERT INTO #Items VALUES (#InputString) -- Diagnostic
DECLARE #Item VARCHAR(8000)
DECLARE #ItemList VARCHAR(8000)
DECLARE #DelimIndex INT
SET #ItemList = #InputString
SET #DelimIndex = CHARINDEX(#Delimiter, #ItemList, 0)
WHILE (#DelimIndex != 0)
BEGIN
SET #Item = SUBSTRING(#ItemList, 0, #DelimIndex)
INSERT INTO #Items VALUES (#Item)
-- Set #ItemList = #ItemList minus one less item
SET #ItemList = SUBSTRING(#ItemList, #DelimIndex+1, LEN(#ItemList)-#DelimIndex)
SET #DelimIndex = CHARINDEX(#Delimiter, #ItemList, 0)
END -- End WHILE
IF #Item IS NOT NULL -- At least one delimiter was encountered in #InputString
BEGIN
SET #Item = #ItemList
INSERT INTO #Items VALUES (#Item)
END
-- No delimiters were encountered in #InputString, so just return #InputString
ELSE INSERT INTO #Items VALUES (#InputString)
RETURN
END -- End Function
GO
---- Set Permissions
--GRANT SELECT ON Split TO UserRole1
--GRANT SELECT ON Split TO UserRole2
--GO
Now, after creating this function, modify your stored procedure to:
CREATE PROCEDURE m1_test #stringCola VARCHAR(max), #stringColb VARCHAR(max)
AS
INSERT INTO m1
SELECT A.Item, B.Item
FROM Split(#stringColA, ',') A
INNER JOIN Split(#stringColB, ',') B ON A.ID = B.ID
GO
As I said in comments this is bad design, but you can do it this way:
INSERT INTO m1 values
SELECT a.d ,
b.d
FROM (SELECT Split.a.value('.', 'VARCHAR(100)') d ,
ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) ) rn
FROM (SELECT CAST('<M>' + REPLACE(#stringCola, ',', '</M><M>') + '</M>' AS XML) d) A
CROSS APPLY d.nodes('/M') AS Split ( a )
) a
JOIN
(SELECT Split.a.value('.', 'VARCHAR(100)') d ,
ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) ) rn
FROM (SELECT CAST('<M>' + REPLACE(#stringColb, ',', '</M><M>') + '</M>' AS XML) d ) A
CROSS APPLY d.nodes('/M') AS Split ( a )
) b ON a.rn = b.rn

Inserting using CSV

I have a table with two fields Name and ID.
Name comes from input parameter #Name and ID comes a CSV #CSVID.
I have a spilt function that return a temp table .
My stored proc is
INSERT INTO dbo.MyTable
(
Name,
ID
)
VALUES
(
(SELECT #Name, id FROM dbo.Split(#CSVID))
)
My split function
ALTER FUNCTION [dbo].[Split] (#InStr VARCHAR(MAX))
RETURNS #TempTab TABLE
(id int not null)
AS
BEGIN
;-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',')
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%,%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO #TempTab(id) VALUES (#VALUE)
END
RETURN
END
So what I want is
say
#Name = 'John Doe'
#CSVID = '1,2'
Then I want the result of insert to be
Name ID
John 1
Jhon 2
I saw so many example but they were all so complicated. I just a simple explanation as to how insert works if the subquery
SELECT * FROM dbo.Split(#CSVID)
returns more than 1 value.
Thanks
INSERT INTO dbo.MyTable(Name, ID)
SELECT #Name,
id
FROM dbo.Split(#CSVID)

Resources