Split column value in SQL and show in next line - sql-server-2008

ID NAME TYPE
1 ABC 1,2,3,4
2 PQR 2,3,5
3 XYZ 1,4
4 TCS 3,1
5 PPP 2,3
I want output like this
ID NAME TYPE
1 ABC 1
2
3
4
2 pqr 2
3
5
and so on

There are two basic challenges with this; splitting the comma separated list of values and then only displaying the first instance of ID and NAME. There may be more efficient or elegant ways to achieve this. However, I have chosen a brute force approach using a cursor. Here you go.
IF OBJECT_ID('tempdb..#Temp', 'U') IS NOT NULL DROP TABLE #Temp;
IF OBJECT_ID('tempdb..#Results', 'U') IS NOT NULL DROP TABLE #Results;
CREATE TABLE #Temp (
ID INT
, NAME CHAR(3)
, TYPE VARCHAR(10)
)
CREATE TABLE #Results (
ID VARCHAR(3)
, NAME CHAR(3)
, TYPE VARCHAR(10)
)
INSERT INTO #Temp (ID, NAME, TYPE) VALUES (1, 'ABC', '1,2,3,4')
INSERT INTO #Temp (ID, NAME, TYPE) VALUES (2, 'PQR', '2,3,5')
INSERT INTO #Temp (ID, NAME, TYPE) VALUES (3, 'XYZ', '1,4')
INSERT INTO #Temp (ID, NAME, TYPE) VALUES (4, 'TCS', '3,1')
INSERT INTO #Temp (ID, NAME, TYPE) VALUES (5, 'PPP', '2,3')
DECLARE #First BIT
DECLARE #ValueList VARCHAR(100)
DECLARE #pos INT
DECLARE #len INT
DECLARE #value VARCHAR(100)
/* declare cursor variables */
DECLARE #ID INT
DECLARE #NAME CHAR(3)
DECLARE #TYPE VARCHAR(10)
DECLARE MyCursor CURSOR FAST_FORWARD READ_ONLY
FOR
SELECT * FROM #Temp
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #ID, #NAME, #TYPE
WHILE ##FETCH_STATUS = 0
BEGIN
SET #ValueList = #TYPE + ','
SET #pos = 0
SET #len = 0
SET #First = 1
WHILE CHARINDEX(',', #ValueList, #pos + 1) > 0
BEGIN
SET #len = CHARINDEX(',', #ValueList, #pos + 1) - #pos
SET #value = SUBSTRING(#ValueList, #pos, #len)
SET #pos = CHARINDEX(',', #ValueList, #pos + #len) + 1
IF (#First = 1)
BEGIN
INSERT INTO #Results (ID, NAME, TYPE) VALUES (#ID, #NAME, #value)
END
ELSE
BEGIN
INSERT INTO #Results (ID, NAME, TYPE) VALUES ('', '', #value)
END
SET #First = 0
END
FETCH NEXT FROM MyCursor INTO #ID, #NAME, #TYPE
END
CLOSE MyCursor
DEALLOCATE MyCursor
SELECT * FROM #Results
Enjoy,
Noel

Related

Insert rows into table with single ID and rows from two comma separated lists

I have two comma separated list which I know belong to a single ID, so I need to insert each corresponding value from the two comma separated list into the table with the common ID.
I have #listA, #listB
and their values would be
#listA ='BRE,CT,DIA,DEXA'
#listB ='2.00,3.00,4.00,5.00'
and I know the ID to which these values belong, say
#SpecID=1
Now what I want is to insert data into a table which contains all three columns like this
Please provide me the steps to approach this problem.
Step 1: I have created the below Function that accepts the Comma separated list items and a Delimiter. It returns the split values along with a RowNumber.
CREATE FUNCTION dbo.SplitString
(
#Delimiter VARCHAR(1),
#InputString VARCHAR(MAX)
)
RETURNS
#ListItems TABLE
(
RowNumber INT,
List VARCHAR(50)
)
AS
BEGIN
DECLARE #Position INT, #RowNumber INT = 1, #ListItem VARCHAR(MAX)
WHILE CHARINDEX(#Delimiter, #InputString) > 0
BEGIN
SELECT #Position = CHARINDEX(#Delimiter, #InputString)
SELECT #ListItem = SUBSTRING(#InputString, 1, #Position-1)
INSERT INTO #ListItems
SELECT #RowNumber,#ListItem
SELECT #InputString = SUBSTRING(#InputString, #Position+1, LEN(#InputString)-#Position)
SET #RowNumber = #RowNumber + 1
END
INSERT INTO #ListItems
Select #RowNumber,#InputString
RETURN
END
Step 2: Using the above function, I split the comma separated list items and created 2 table variables.
DECLARE #listA VARCHAR(MAX), #listB VARCHAR(MAX), #SpecID INT, #Delimiter VARCHAR(1)
SET #listA= 'BRE,CT,DIA,DEXA'
SET #listB ='2.00,3.00,4.00,5.00'
SET #SpecID = 1
SET #Delimiter = ','
DECLARE #ListItems Table
(
SpecID INT,
listA VARCHAR(50),
listB VARCHAR(50)
)
DECLARE #TableListA Table
(
RowNumber INT,
ListA VARCHAR(50)
)
DECLARE #TableListB Table
(
RowNumber INT,
ListB VARCHAR(50)
)
INSERT INTO #TableListA
SELECT * FROM SplitString(#Delimiter,#listA)
INSERT INTO #TableListB
SELECT * FROM SplitString(#Delimiter,#listB)
INSERT INTO #ListItems
SELECT
#SpecID,
A.ListA,
B.ListB
FROM #TableListA A
INNER JOIN #TableListB B ON B.RowNumber = A.RowNumber
SELECT * FROM #ListItems
Please use the SQL Fiddle to check the output: http://sqlfiddle.com/#!6/9e12b/1/0
You will have to do it like this:
1) Split using `,`
2) Have 2 arrays
3) Both need to have the same size so iterate over 1 array
4) Use the index within the loop to insert the values.

Convert csv values to table

DATA:
id data
114 10047,10001,10003
123 90080
233 10020,10029,10032,10065
TABLE:
DECLARE #TEMP TABLE (id int
,data varchar(50)
PRIMARY KEY (id)
)
INSERT INTO #TEMP VALUES (114,'10047,10001,10003')
INSERT INTO #TEMP VALUES (123,'90080')
INSERT INTO #TEMP VALUES (233,'10020,10029,10032,10065')
Given the above data I am trying to convert the comma separated values to a table so I can join the values, I already have a function that works fine by taking a single value as a parameter, how do I call the function so that it goes through each of the rows above (without using cursors) and outputs the values as such :
id data
114 10047
114 10001
114 10003
123 90080
233 10020
233 10029
233 10032
233 10065
Function:
FUNCTION [dbo].[ConvertCsvToTable](#csvList nvarchar(MAX))
RETURNS #csvTable table([id] int NOT NULL)
AS
BEGIN
DECLARE #pos int
DECLARE #nextPos int
DECLARE #valueLen int
SELECT #pos = 0, #nextPos = 1
WHILE #nextPos > 0
BEGIN
SELECT #nextPos = charindex(',', #csvList, #pos + 1)
SELECT #valueLen = CASE WHEN #nextPos > 0
THEN #nextPos
ELSE len(#csvList) + 1
END - #pos - 1
INSERT #csvTable (id)
VALUES (convert(int, substring(#csvList, #pos + 1, #valueLen)))
SELECT #pos = #nextPos
END
RETURN
END
You can use simplier solution if you convert your comma separated values to XML data. Your result could be achieved with a single select statement like as follows:
-- Improve table structure adding XML field
DECLARE #TEMP TABLE (id int
,data varchar(50)
,xmldata xml
PRIMARY KEY (id)
)
-- Your initial data
INSERT INTO #TEMP VALUES (114,'10047,10001,10003',null)
INSERT INTO #TEMP VALUES (123,'90080',null)
INSERT INTO #TEMP VALUES (233,'10020,10029,10032,10065',null)
-- Transforming CSV string to XML
UPDATE #TEMP
SET xmldata = CONVERT(XML, '<DATA><RAW>'+REPLACE(data, ',', '</RAW><RAW>')+'</RAW></DATA>')
-- Query XML data to obtain required result
SELECT t.id,
x.xmldata.value('(.)[1]','INT') AS data
FROM #TEMP t
CROSS APPLY t.xmldata.nodes('/DATA/RAW') x(xmldata);

Ms Sql Function for list

I have varchar values like below
72,73,74
I try to split as a comma after that i want to convert to int above values.Than i want to match Id with my User Table.
CREATE FUNCTION Fn_MyFunction(#MyUserIdValues VARCHAR(100))
RETURNS VARCHAR(300) AS
BEGIN
DECLARE #Result VARCHAR(300) = ''
Select UserName From UserTable
Where MyUserIdValues=UserIdValues
RETURN #Result
#Result must be like below in one column
Joe,Michael,Ricky
Any help will be appreciated.
Thanks.
The classic way of doing this...
/*
create table Users
(
id int,
name nvarchar(max)
)
insert into Users
values
(72, 'Joe'),
(73, 'Michael'),
(74, 'Ricky'),
(75, 'Manny'),
(76, 'Bob')
*/
CREATE FUNCTION dbo.Fn_MyFunction(#IdValues VARCHAR(100))
RETURNS NVARCHAR(max) AS
BEGIN
DECLARE #Result NVARCHAR(max);
DECLARE #delimiter as nchar = ',';
WHILE LEN(#IdValues) <> 0
BEGIN
Declare #CurrentId int;
If CHARINDEX(#delimiter, #IdValues) = 0
begin
Set #CurrentId = cast(#IdValues as int);
Set #IdValues = ''
End
Else
begin
Set #CurrentId = cast(left(#IdValues, charindex(#delimiter, #IdValues) -1) as int)
Set #IdValues = Substring(#IdValues, charindex(#delimiter, #IdValues) +1, len(#IdValues))
End
select #Result = Isnull(#Result + ',', '') + Isnull((Select Name From Users Where Id=#CurrentId),'(unknown)')
END
RETURN #Result
END
GO
Select dbo.Fn_MyFunction('72,73,74')
--Joe,Michael,Ricky
Select dbo.Fn_MyFunction('72,0,74')
--Joe,(unknown),Ricky
Select dbo.Fn_MyFunction('72,73,72,74,74')
--Joe,Michael,Joe,Ricky,Ricky
GROUP_CONCAT and FIND_IN_SET might be a handy for you.
Try this:
SELECT GROUP_CONCAT(UserName)
FROM UserTable
WHERE FIND_IN_SET(MyUserIdValues,'72,73,74');
I had found solution for splitting string and inserting it in a table
GO
/****** Object: UserDefinedFunction [dbo].[Split] Script Date: 10/03/2013 11:45:16 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[Split] (
#InputString VARCHAR(8000),
#Delimiter VARCHAR(50)
)
RETURNS #Items TABLE (
Item int
)
AS
BEGIN
IF #Delimiter = ' '
BEGIN
SET #Delimiter = ','
SET #InputString = REPLACE(#InputString, ' ', #Delimiter)
END
IF (#Delimiter IS NULL OR #Delimiter = '')
SET #Delimiter = ','
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 (cast(#InputString as int))
RETURN
END -- End Function
Select UserName From UserTable where MyUserIdValues in(Select Item from Split('72,73,74',','))
//Call function Split using last query
Check this out, it will solve your problem and it simple and perfect method
Select Username from UserTable where MyUserIdValues IN ' + '('+ #Id +')'
My attempt (i think it's a little neater):
create function dbo.fn_UserNames(#ids varchar(max))
returns varchar(max) as
begin
set #ids = #ids + ','
declare #id table (Id int)
while(#ids != '') begin
insert into #id
select i
from (select substring(#ids, 1, charindex(',', #ids, 0) - 1) i) a
where i != ''
if #ids like '%,%'
set #ids = substring(#ids, charindex(',', #ids, 0) + 1,
len(#ids) - charindex(',', #ids, 0))
else
set #ids = ''
end
declare #ret varchar(max)
select #ret = isnull(#ret, '') + a.UserName + ','
from adhoc.UserTable a
join #id b on a.UserId = b.Id
return #ret
end
Hi you can try this one also.
CREATE FUNCTION [DBO].[FN_SPLIT] ( #STRSTRING VARCHAR(MAX))
RETURNS #NAME TABLE (NAME VARCHAR(MAX))
AS
BEGIN
DECLARE #USERID TABLE(ID INT)
DECLARE #USERS TABLE (ID INT , NAME VARCHAR(50))
INSERT INTO #USERS VALUES (72,'A'),(73,'B'),(74,'C')
;WITH STR_CTE(_START, _STOP) AS
(
SELECT 1, CHARINDEX(',' , #STRSTRING )
UNION ALL
SELECT CAST(_STOP + 1 AS INT), CHARINDEX(',' ,#STRSTRING , CAST((_STOP + 1) AS INT))
FROM
STR_CTE
WHERE _STOP > 0
)
INSERT INTO #USERID (ID)
SELECT
SUBSTRING(#STRSTRING , _START, CASE WHEN _STOP > 0 THEN _STOP -_START ELSE 4000 END) AS ID
FROM STR_CTE
DECLARE #STRNAME VARCHAR(MAX)
SELECT
#STRNAME = COALESCE(#STRNAME+',','') + U.NAME
FROM
#USERID UD
INNER JOIN
#USERS U ON UD.ID = U.ID
INSERT INTO #NAME
SELECT #STRNAME
RETURN;
END

Need a qry to join a comma separated column with another table with its Id in it to find the code

I have a table with
Table name TB1
mpeFromWHId mpeToStoreList
8 16,18,24
and Table tb2 are the codes of the comma separated storeid
nlid nlcode
16 ncl
18 mcl
24 dcl
I need a query that will result in
col1 Col2
8 ncl,mcl,dcl
First you need a function to parse comma delimited string into table, you can use this (found [here])1:
CREATE FUNCTION [dbo].Split1(#input AS Varchar(4000) )
RETURNS
#Result TABLE(Value BIGINT)
AS
BEGIN
DECLARE #str VARCHAR(20)
DECLARE #ind Int
IF(#input is not null)
BEGIN
SET #ind = CharIndex(',',#input)
WHILE #ind > 0
BEGIN
SET #str = SUBSTRING(#input,1,#ind-1)
SET #input = SUBSTRING(#input,#ind+1,LEN(#input)-#ind)
INSERT INTO #Result values (#str)
SET #ind = CharIndex(',',#input)
END
SET #str = #input
INSERT INTO #Result values (#str)
END
RETURN
END
Then you can use something like this (but there are many more options off course):
declare #searchId int
set #searchId = 8
declare #tb1 table (mpeFromWHId int, mpeToStoreList varchar(100))
insert into #tb1
select 8, '16,18,24'
declare #tb2 table (nlid int, nlcode varchar(30))
insert into #tb2
select 16, 'ncl' union
select 18, 'mcl' union
select 24, 'dcl'
select stuff((
select ',' + nlcode
from #tb2
where nlid in (
select Value
from dbo.Split1((select mpeToStoreList from #tb1 where mpeFromWHId = #searchId))
)
order by nlcode
for xml path(''), type
).value('(./text())[1]','varchar(max)'), 1, 2, '')
If you don't want to create a user function, you can do like this:
;with TB1(mpeFromWHId, mpeToStoreList) AS (
select 8,'16,18,24'
)
SELECT t.mpeFromWHId,n.ID FROM (
select *,convert(XML,'<n>'+replace(mpeToStoreList,',','</n><n>')+'</n>') as x from tb1
) AS t
cross apply(select s.b.value('.','INT') as ID from t.x.nodes('n') s(b)) n
mpeFromWHId ID
8 16
8 18
8 24

How can I insert values into table like Bulk Insert?

I have values like
string a,b;
a= "1,2,3,4";
b="admin";
I am passing a and b to SP and I want to save it in DB like
a b
1 admin
2 admin
3 admin
4 admin
How can I do this? Can someone give me some ideas on how to do it?
Thank you..
SQL doesn't have a concept of arrays, so this gets a bit interesting.
Pass a list as a string parameter:
DECLARE #INSTR as VARCHAR(MAX)
SET #INSTR = '2,3,177,'
DECLARE #SEPERATOR as VARCHAR(1)
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
SET #SEPERATOR = ','
WHILE PATINDEX('%' + #SEPERATOR + '%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%' + #SEPERATOR + '%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO myTable (a, b) VALUES (#VALUE, 'admin')
END