separate comma separated values and store in table in sql server
You will need to create a split function similar to this:
create FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))
returns @temptable TABLE (items varchar(MAX))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end;
Then in your stored procedure, you will call the function to split your string:
ALTER PROCEDURE [dbo].[spInsertDistributionRuleListType]
(
@Rule_ID int,
@ListType_ID int,
@Values VARCHAR(MAX)=NULL
)
AS
BEGIN
INSERT INTO DistributionRule_x_ListType (Rule_ID, ListType_ID, Value)
SELECT @Rule_ID, @ListType_ID, items
FROM [dbo].[Split] (@Values, ',') -- call the split function
END
When you execute the stored procedure, it will split the values and insert the multiple rows into your table:
exec spInsertDistributionRuleListType 1, 2, '319,400,521,8465,2013';
See SQL Fiddle with Demo. This will insert the following result:
| RULE_ID | LISTTYPE_ID | VALUE |
---------------------------------
| 1 | 1 | 10 |
| 1 | 2 | 319 |
| 1 | 2 | 400 |
| 1 | 2 | 521 |
| 1 | 2 | 8465 |
| 1 | 2 | 2013 |
How to split a comma-separated value to columns
CREATE FUNCTION [dbo].[fn_split_string_to_column] (
@string NVARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @out_put TABLE (
[column_id] INT IDENTITY(1, 1) NOT NULL,
[value] NVARCHAR(MAX)
)
AS
BEGIN
DECLARE @value NVARCHAR(MAX),
@pos INT = 0,
@len INT = 0
SET @string = CASE
WHEN RIGHT(@string, 1) != @delimiter
THEN @string + @delimiter
ELSE @string
END
WHILE CHARINDEX(@delimiter, @string, @pos + 1) > 0
BEGIN
SET @len = CHARINDEX(@delimiter, @string, @pos + 1) - @pos
SET @value = SUBSTRING(@string, @pos, @len)
INSERT INTO @out_put ([value])
SELECT LTRIM(RTRIM(@value)) AS [column]
SET @pos = CHARINDEX(@delimiter, @string, @pos + @len) + 1
END
RETURN
END
Save a comma separated array in a string in a table
You can use string_split()
in the most recent versions of SQL Server:
SELECT ID, Name, ss.value as subject
FROM Students s CROSS APPLY
string_split(s.subjects, ',') ss;
You can also play with JSON or define your own split()
function, although in older versions, I would just use a recursive CTE:
with cte as (
select s.id, convert(varchar(max), null) as subject, convert(varchar(max), subjects + ',') as rest
from students s
union all
select id, left(rest, charindex(',', rest) - 1),
stuff(rest, 1, charindex(',', rest), '')
from cte
where rest <> ''
)
select *
from cte
where subject is not null;
Here is a db<>fiddle.
Split comma delimited string and insert to a table (int)
Using the Split()
function you have mentioned in comments,
-- Variable holding comma separated values
DECLARE @Var VARCHAR(4000);
SET @Var = '188,189,190,191,192,193,194'
-- Test Target Table
DECLARE @Target_Table TABLE (First_ID INT,Second_ID INT,Third_ID INT)
-- Insert statement
INSERT INTO @Target_Table
SELECT 1, CAST(Items AS INT) , 0
FROM dbo.Split(@Var, ',')
-- Test Select
SELECT * FROM @Target_Table
Result Set
╔══════════╦═══════════╦══════════╗
║ First_ID ║ Second_ID ║ Third_ID ║
╠══════════╬═══════════╬══════════╣
║ 1 ║ 188 ║ 0 ║
║ 1 ║ 189 ║ 0 ║
║ 1 ║ 190 ║ 0 ║
║ 1 ║ 191 ║ 0 ║
║ 1 ║ 192 ║ 0 ║
║ 1 ║ 193 ║ 0 ║
║ 1 ║ 194 ║ 0 ║
╚══════════╩═══════════╩══════════╝
Split Comma Separated values into multiple column
Your sample data may not need any splitting. You want to move the data to a column based on the value it finds. You can do this a bit simpler than splitting the data. This works just fine for your sample data.
declare @Something table
(
Combined_Column varchar(10)
)
insert @Something values
('1,2,3')
, ('2')
, ('1,3')
, ('1,2,3,4')
, ('1,3,4')
, ('1')
, ('4')
select *
, col1 = case when charindex('1', s.Combined_Column) > 0 then 1 end
, col2 = case when charindex('2', s.Combined_Column) > 0 then 2 end
, col3 = case when charindex('3', s.Combined_Column) > 0 then 3 end
, col4 = case when charindex('4', s.Combined_Column) > 0 then 4 end
from @Something s
Split comma separated values into target table with fixed number of columns
It is typically bad design to store CSV values in a single column. If at all possible, use an array or a properly normalized design instead.
While stuck with your current situation ...
For known small maximum number of elements
A simple solution without trickery or recursion will do:
SELECT id, 1 AS rnk
, split_part(csv, ', ', 1) AS c1
, split_part(csv, ', ', 2) AS c2
, split_part(csv, ', ', 3) AS c3
, split_part(csv, ', ', 4) AS c4
, split_part(csv, ', ', 5) AS c5
FROM tbl
WHERE split_part(csv, ', ', 1) <> '' -- skip empty rows
UNION ALL
SELECT id, 2
, split_part(csv, ', ', 6)
, split_part(csv, ', ', 7)
, split_part(csv, ', ', 8)
, split_part(csv, ', ', 9)
, split_part(csv, ', ', 10)
FROM tbl
WHERE split_part(csv, ', ', 6) <> '' -- skip empty rows
-- three more blocks to cover a maximum "around 20"
ORDER BY id, rnk;
db<>fiddle here
id
being the PK of the original table.
This assumes ', ' as separator, obviously.
You can adapt easily.
Related:
- Split comma separated column data into additional columns
For unknown number of elements
Various ways. One way use regexp_replace()
to replace every fifth separator before unnesting ...
-- for any number of elements
SELECT t.id, c.rnk
, split_part(c.csv5, ', ', 1) AS c1
, split_part(c.csv5, ', ', 2) AS c2
, split_part(c.csv5, ', ', 3) AS c3
, split_part(c.csv5, ', ', 4) AS c4
, split_part(c.csv5, ', ', 5) AS c5
FROM tbl t
, unnest(string_to_array(regexp_replace(csv, '((?:.*?,){4}.*?),', '\1;', 'g'), '; ')) WITH ORDINALITY c(csv5, rnk)
ORDER BY t.id, c.rnk;
db<>fiddle here
This assumes that the chosen separator ;
never appears in your strings. (Just like ,
can never appear.)
The regular expression pattern is the key: '((?:.*?,){4}.*?),'
(?:)
... “non-capturing” set of parentheses()
... “capturing” set of parentheses*?
... non-greedy quantifier{4}?
... sequence of exactly 4 matches
The replacement '\1;'
contains the back-reference \1
.
'g'
as fourth function parameter is required for repeated replacement.
Further reading:
- PostgreSQL & regexp_split_to_array + unnest
- Apply `trim()` and `regexp_replace()` on text array
- PostgreSQL unnest() with element number
Other ways to solve this include a recursive CTE or a set-returning function ...
Fill from right to left
(Like you added in How to put values starting from the right side into columns?)
Simply count down numbers like:
SELECT t.id, c.rnk
, split_part(c.csv5, ', ', 5) AS c1
, split_part(c.csv5, ', ', 4) AS c2
, split_part(c.csv5, ', ', 3) AS c3
, split_part(c.csv5, ', ', 2) AS c4
, split_part(c.csv5, ', ', 1) AS c5
FROM ...
db<>fiddle here
Comma Separated Values in one table to return results from another table
As a starter: don't store multiple values in a single column; don't use strings to store numbers. You can have a look at this famous SO post for more details on why this is discouraged.
That said, a simple (although inefficient) solution to search for a value in a CSV list is:
select t1.FirstName + ' ' + t1.Lastname as fullname, t2.Postcode, t2.HouseNo
from t1
join t2 on concat(', ', t2.id, ', ') like concat('%, ', t1.id, ', %')
where t1.active = 1
This assumes that you consistently use a comma + a space (', '
) as separator between list elements.
Related Topics
Varbinary to String on SQL Server
Explode (Transpose) Multiple Columns in Spark SQL Table
How to Use Boolean Type in Select Statement
What Does Delimiter // Do in a Trigger
Creating Temporary Tables in SQL
Mysql: What Is a Reverse Version of Like
SQL Server Select Distinct Rows Using Most Recent Value Only
How to Insert Values into a Table, Using a Subquery with More Than One Result
How to Do a Max(Count(*)) in SQL
How to Count Instances of Character in SQL Column
Generate a Range of Dates Using SQL
Postgresql: Encoding Problems on Windows When Using Psql Command Line Utility
What's the Proper Index for Querying Structures in Arrays in Postgres JSONb
Difference Between Byte and Char in Column Datatypes
Pivot Table and Concatenate Columns
Why Can't I Seem to Force Oracle 11G to Consume More Cpus for a Single SQL Query