web-dev-qa-db-fra.com

Diviser les données de colonne séparées par des virgules en colonnes supplémentaires

J'ai des données séparées par des virgules dans une colonne:

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

Je veux diviser les données séparées par des virgules en plusieurs colonnes pour obtenir cette sortie:

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

Comment cela peut il etre accompli?

58
Gallop

Si le nombre de champs dans le fichier CSV est constant, vous pouvez procéder comme suit:

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

Par exemple:

=> 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)

Si le nombre de champs dans le fichier CSV n'est pas constant, vous pouvez obtenir le nombre maximal de champs avec quelque chose comme ceci:

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

puis construisez la liste de colonnes a[1], a[2], ..., a[M] appropriée pour votre requête. Donc, si ce qui précède vous donnait un maximum de 6, vous utiliseriez ceci:

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)

Vous pouvez combiner ces deux requêtes dans une fonction si vous le souhaitez.

Par exemple, donnez ces données (c'est un NULL dans la dernière ligne):

=> 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)

Puisque votre délimiteur est une simple chaîne fixe, vous pouvez également utiliser string_to_array au lieu de regexp_split_to_array:

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

Merci à Michael pour le rappel concernant cette fonction.

Vous devez vraiment repenser votre schéma de base de données pour éviter autant que possible la colonne CSV. Vous devriez plutôt utiliser une colonne de tableau ou une table séparée.

61
mu is too short

split_part() fait ce que vous voulez en une étape:

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;

Ajoutez autant de lignes que vous avez d'éléments dans col (maximum possible). Les colonnes dépassant les éléments de données seront des chaînes vides ('').

89
Erwin Brandstetter

Vous pouvez utiliser la fonction split.

    SELECT 
    (select top 1 item from dbo.Split(FullName,',') where id=1 ) Column1,
    (select top 1 item from dbo.Split(FullName,',') where id=2 ) Column2,
    (select top 1 item from dbo.Split(FullName,',') where id=3 ) Column3,
    (select top 1 item from dbo.Split(FullName,',') where id=4 ) Column4,
    FROM MyTbl
1
vicky