Create a function to split delimited string into a table - mysql

In order to split delimited string, I would need the creation of a function returning a table and taking a comma separated string as parameter.
For instance, have a look at this input table:
Using the function, the result would be:
In this case, the delimited string is the Person column that should be taken as parameter.
Thanks in advance.

Try this one
--Build Schema for Your Case
DECLARE #TAB TABLE (ID INT, NAME VARCHAR(1000))
INSERT INTO #TAB
SELECT 1,'Pravesh,Simon'
UNION ALL
SELECT 2,'Me,Myself,I'
--Used Recursive CTE to achieve Tabular view of Comma Separated Column
--Used While loop to take next row
--Used Table Variable #RESULT to store your Result Set
DECLARE #ID INT, #T VARCHAR(100), #SNO INT= 1, #MAX_SNO INT
DECLARE #RESULT TABLE (ID INT, NAME VARCHAR(1000))
SELECT #SNO=1, #MAX_SNO =MAX(ID) FROM #TAB
WHILE(#SNO<=#MAX_SNO)
BEGIN
SELECT #ID = ID, #T = NAME FROM #TAB WHERE ID=#SNO
SET #T =#T+','
;WITH MyCTE(Start,[End]) AS(
SELECT 1 AS Start,CHARINDEX(',',#T,1) AS [End]
UNION ALL
SELECT [End]+1 AS Start,CHARINDEX(',',#T,[End]+1)AS [End]
from MyCTE where [End]<LEN(#T)
)
INSERT INTO #RESULT
Select #SNO AS ID, SUBSTRING(#T,Start,[End]-Start) NAME from MyCTE;
SET #SNO+=1
END
--Getting Result Set
SELECT * FROM #RESULT
Edit: From Your Comments
If you want to do the above with a function, this one far easy than above looping.
CREATE FUNCTION [DBO].[FN_SPLIT_STR_TO_COL] (#T AS VARCHAR(4000) )
RETURNS
#RESULT TABLE(VALUE VARCHAR(250))
AS
BEGIN
SET #T= #T+','
;WITH MYCTE(START,[END]) AS(
SELECT 1 AS START,CHARINDEX(',',#T,1) AS [END]
UNION ALL
SELECT [END]+1 AS START,CHARINDEX(',',#T,[END]+1)AS [END]
FROM MYCTE WHERE [END]<LEN(#T)
)
INSERT INTO #RESULT
SELECT SUBSTRING(#T,START,[END]-START) NAME FROM MYCTE;
RETURN
END
Now just call the function for every row by passing column to it.
With Cross Apply
SELECT ID,FN_RS.VALUE FROM #TAB
CROSS APPLY
(SELECT * FROM [DBO].[FN_SPLIT_STR_TO_COL] (NAME)) AS FN_RS

TRY THIS QUERY
//Which will work only when having 3 comma only
SELECT Id,SUBSTRING_INDEX(SUBSTRING_INDEX(`Person`, ',', 1), ',', -1) as Person
FROM `table`
UNION
select Id,SUBSTRING_INDEX(SUBSTRING_INDEX(`Person`, ',', 2), ',', -1) as Person
FROM `table`
UNION
select Id,SUBSTRING_INDEX(SUBSTRING_INDEX(`Person`, ',', 3), ',', -1) as Person
FROM `table`
order by Id ASC

create function [dbo].[udf_splitstring] (#tokens varchar(max),
#delimiter varchar(5))
returns #split table (
token varchar(200) not null )
as
begin
declare #list xml
select #list = cast('<a>'
+ replace(#tokens, #delimiter, '</a><a>')
+ '</a>' as xml)
insert into #split
(token)
select ltrim(t.value('.', 'varchar(200)')) as data
from #list.nodes('/a') as x(t)
return
end
create table #dup
( id int, name varchar(100)
)
insert into #dup values
(1,'leela,venkatesh,don'),
(2,'john,smith,lewis')
select id,b.token from #dup
cross apply
(select token from udf_splitstring(name,',') )b

Related

How to pass comma separated value to a stored procedure directly in SQL

How to pass comma separated value to a stored procedure directly in SQLSERVER?
ALTER PROCEDURE [dbo].[CM_GetUnreadCount_ByUserJid_bilal_onlyfortesting] (#UserID AS VARCHAR(MAX))
AS
DECLARE #myTable TABLE (
MessageId BIGINT,
RecieverId VARCHAR(100)
)
INSERT INTO #myTable (
MessageId,
RecieverId
)
SELECT MAX(MessageID),
ReceiverID
FROM dbo.CM_MessageStatus
WHERE ReceiverID IN (#UserID)
AND DeliveredDate IS NOT NULL
GROUP BY ReceiverID
EXEC [CM_GetUnreadCount_ByUserJid_bilal_onlyfortesting] '123', '456'
Error:
Msg 8144, Level 16, State 2, Procedure
CM_GetUnreadCount_ByUserJid_bilal_onlyfortesting, Line 0 Procedure or
function CM_GetUnreadCount_ByUserJid_bilal_onlyfortesting has too many
arguments specified.
You need to write
exec [CM_GetUnreadCount_ByUserJid_bilal_onlyfortesting] '123,456'
And then you need to string_split it inside your stored procedure, just like this:
Notice - You can only use string_split in 2016 otherwise you need to do something else like XML PATH
CREATE PROCEDURE [dbo].[CM_GetUnreadCount_ByUserJid_bilal_onlyfortesting] ( #UserID AS VARCHAR(MAX))
AS
DECLARE #myTable TABLE
(
MessageId BIGINT,
RecieverId VARCHAR(100)
)
DECLARE #UserTable TABLE
( UserId varchar(MAX)
)
INSERT INTO #UserTable (UserID)
select * from string_split(#UserID,',');
INSERT INTO #myTable
( MessageId, RecieverId )
SELECT MAX(MessageID),RecieverID
FROM dbo.Message_status
WHERE RecieverID IN (select * from #UserTable)
AND DeliveredDate IS NOT NULL
GROUP BY RecieverID
--RETURN OUTPUT TO TEST
Select * from #myTable

Loop through a split string variable to insert rows in a stored procedure in SQL Server 2008

I am working on SQL Server 2008 to create a stored procedure that:
takes a string variable like this: '1,2,3'
splits the string using a table-valued function to get each value separately
and then inserts each value into a new row in a table
What I am trying to do is something like this:
WHILE (select vlaue FROM dbo.SplitString('1,2,3',',')) has rows
insert into TableName (col1,col2) values (col1Data, value)
I am having a hard time trying to find the right syntax for this.
I use this Table-valued function:
CREATE FUNCTION [dbo].[Split] (#sep char(1), #s varchar(512))
RETURNS table
AS
RETURN (
WITH Pieces(pn, start, stop) AS (
SELECT 1, 1, CHARINDEX(#sep, #s)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(#sep, #s, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT pn,
SUBSTRING(#s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
FROM Pieces
)
GO
Which takes a string with a separator and returns a table with two columns the first returns a 1-based position and the second the element at that position in the string:
Usage:
SELECT * FROM dbo.Split(',', '1,2,3')
Returns:
pn s
1 1
2 2
3 3
To Insert results into a table:
INSERT INTO TableName (Col1)
SELECT S FROM dbo.Split(',', '1,2,3)
For your specific example change your syntax to be:
insert into TableName (col1,col2)
select col1Data, value FROM dbo.SplitString('1,2,3',',')
The typical INSERT INTO ... SELECT ... should do:
INSERT INTO TableName (col1,col2)
SELECT #col1Data,value FROM dbo.SplitString('1,2,3',','))
If someone else is looking for this, I was about to make a split function as several answers mentioned but noticed there's a built-in function that does this already.
string_split was added in MSSQL 2016.
INSERT INTO Project.FormDropdownAnswers (FkTableId, CreatedBy, CreatedDate)
SELECT 123, TRY_CAST(value AS INT), #username, getdate()
FROM string_split('44,45,46,47,55',',')
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql
CREATE TABLE tablename
(
id SMALLINT ,
value INT
)
INSERT INTO tablename ( id, value )
SELECT * FROM dbo.Split('1,2,3',',')
try this....
If need to use as variables there is 2 nice options:
Procedure MF_SPLIT
CREATE PROC [MF_SPLIT] (#ELS NVARCHAR(MAX)=NULL OUTPUT, #RET NVARCHAR(MAX)=NULL OUTPUT, #PROC NVARCHAR(MAX)=NULL) AS BEGIN
IF #ELS IS NULL BEGIN
PRINT ' #ELS
List of elements in string (OUTPUT)
#RET
Next return (OUTPUT)
#PROC
NULL = '','', content to do split
Example:
DECLARE #NAMES VARCHAR(100) = ''ERICK,DE,VATHAIRE''
DECLARE #N VARCHAR(100)
WHILE #NAMES IS NOT NULL BEGIN
EXEC MF_SPLIT #NAMES OUTPUT, #N OUTPUT
SELECT List = #NAMES, ActiveWord = #N
END'
RETURN
END
SET #PROC = ISNULL(#PROC, ',')
IF CHARINDEX(#PROC, #ELS) = 0 BEGIN
SELECT #RET = #ELS, #ELS = NULL
RETURN
END
SELECT
#RET = LEFT(#ELS, CHARINDEX(#PROC, #ELS) - 1)
, #ELS = STUFF(#ELS, 1, LEN(#RET) + 1, '')
END
Usage:
DECLARE #NAMES VARCHAR(100) = '1,2,3'
DECLARE #N VARCHAR(100)
WHILE #NAMES IS NOT NULL BEGIN
EXEC MF_SPLIT #NAMES OUTPUT, #N OUTPUT
SELECT List = #NAMES, ActiveWord = #N
END
Procedure MF_SPLIT_DO (Depends of MF_SPLIT), less sintax to use BUT the code will be in a string and use default variable "#X"
CREATE PROC MF_SPLIT_DO (#ARR NVARCHAR(MAX), #DO NVARCHAR(MAX)) AS BEGIN
--Less sintax
DECLARE #X NVARCHAR(MAX)
WHILE #ARR IS NOT NULL BEGIN
EXEC MF_SPLIT #ARR OUT, #X OUT
EXEC SP_EXECUTESQL #DO, N'#X NVARCHAR(MAX)', #X
END
END
Usage:
EXEC MF_SPLIT_DO '1,2,3', 'SELECT #X'

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.

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

stored procedure for inserting comma seperated values in table using ms sql?

I have a table named assignRole.
I am passing string of userid (int) csv ,and passing roleid(int).
I want a stored procedure which split userid from string and take roleid and insert these values in table.this thing is to happen for all values in userid string.
First, create a function:
CREATE FUNCTION [dbo].[SplitInts]
(
#List VARCHAR(MAX),
#Delimiter CHAR(1)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM (
SELECT Item = x.i.value('(./text())[1]', 'int') FROM (
SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.') ) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL
);
Now you can say:
INSERT dbo.assignRole(RoleID, UserID)
SELECT #RoleID, Item
FROM dbo.SplitInts(#UserIDList, ',');
I like to use a table-valued function to do the split.
IF OBJECT_ID (N'dbo.StrSplit') IS NOT NULL DROP FUNCTION dbo.[StrSplit]
GO
CREATE FUNCTION [dbo].[StrSplit]
(
#String VARCHAR(MAX), #Delimiter char(1)
)
RETURNS
#Results TABLE (
Items NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(MAX)
-- HAVE TO SET TO 1 SO IT DOESNT EQUAL ZERO FIRST TIME IN LOOP
SELECT #INDEX = 1
-- Early exit if passed string is null
IF #String IS NULL RETURN
WHILE #INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX !=0
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results(Items) VALUES(#SLICE)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0 BREAK
END
RETURN
END
GO
GRANT SELECT ON [dbo].[StrSplit] TO [public]