Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split comma separated column data into additional columns

I have comma separated data in a column:

Column  -------  a,b,c,d  

I want to split the comma separated data into multiple columns to get this output:

Column1  Column2 Column3 Column4  -------  ------- ------- ------- a        b       c       d  

How can this be achieved?

like image 965
Gallop Avatar asked Dec 21 '11 04:12

Gallop


People also ask

How split comma separated value to multiple Columns in SQL Server?

Lets split the comma separated phone number list into columns, For this we will use Cross Apply operator, String_Split function and SQL pivot. Following query is used for splitting a comma separated phone number list into columns.


2 Answers

split_part() does what you want in one step:

SELECT split_part(col, ',', 1) AS col1      , split_part(col, ',', 2) AS col2      , split_part(col, ',', 3) AS col3      , split_part(col, ',', 4) AS col4 FROM   tbl; 

Add as many lines as you have items in col (the possible maximum).
Columns exceeding data items will be empty strings ('').

like image 112
Erwin Brandstetter Avatar answered Sep 22 '22 23:09

Erwin Brandstetter


If the number of fields in the CSV is constant then you could do something like this:

select a[1], a[2], a[3], a[4] from (     select regexp_split_to_array('a,b,c,d', ',') ) as dt(a) 

For example:

=> select a[1], a[2], a[3], a[4] from (select regexp_split_to_array('a,b,c,d', ',')) as dt(a);  a | a | a | a  ---+---+---+---  a | b | c | d (1 row) 

If the number of fields in the CSV is not constant then you could get the maximum number of fields with something like this:

select max(array_length(regexp_split_to_array(csv, ','), 1)) from your_table 

and then build the appropriate a[1], a[2], ..., a[M] column list for your query. So if the above gave you a max of 6, you'd use this:

select a[1], a[2], a[3], a[4], a[5], a[6] from (     select regexp_split_to_array(csv, ',')     from your_table ) as dt(a) 

You could combine those two queries into a function if you wanted.

For example, give this data (that's a NULL in the last row):

=> select * from csvs;      csv      -------------  1,2,3  1,2,3,4  1,2,3,4,5,6  (4 rows)  => select max(array_length(regexp_split_to_array(csv, ','), 1)) from csvs;  max  -----    6 (1 row)  => select a[1], a[2], a[3], a[4], a[5], a[6] from (select regexp_split_to_array(csv, ',') from csvs) as dt(a);  a | a | a | a | a | a  ---+---+---+---+---+---  1 | 2 | 3 |   |   |   1 | 2 | 3 | 4 |   |   1 | 2 | 3 | 4 | 5 | 6    |   |   |   |   |  (4 rows) 

Since your delimiter is a simple fixed string, you could also use string_to_array instead of regexp_split_to_array:

select ... from (     select string_to_array(csv, ',')     from csvs ) as dt(a); 

Thanks to Michael for the reminder about this function.

You really should redesign your database schema to avoid the CSV column if at all possible. You should be using an array column or a separate table instead.

like image 39
mu is too short Avatar answered Sep 20 '22 23:09

mu is too short