PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Diviser les valeurs séparées par des virgules dans la table cible avec un nombre fixe de colonnes

Il est généralement mal conçu de stocker les valeurs CSV dans une seule colonne. Si possible, utilisez plutôt un tableau ou une conception correctement normalisée.

Bien que coincé avec votre situation actuelle ...

Pour un petit nombre maximum d'éléments connu

Une solution simple sans ruse ni récursivité fera l'affaire :

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<>violon ici

id étant le PK de la table d'origine.
Cela suppose ', ' comme séparateur, évidemment.
Vous pouvez vous adapter facilement.

Connexe :

Pour un nombre inconnu d'éléments

Différentes manières. Une façon d'utiliser regexp_replace() pour remplacer un séparateur sur cinq avant de désimbriquer...

-- 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<>violon ici

Cela suppose que le séparateur choisi ; jamais apparaît dans vos chaînes. (Tout comme , ne peut jamais apparaître.)

Le modèle d'expression régulière est la clé :'((?:.*?,){4}.*?),'

(?:) ... ensemble de parenthèses "sans capture"
() ... "capturer" un ensemble de parenthèses
*? ...
quantificateur non gourmand
{4}? ... suite d'exactement 4 correspondances

Le remplacement '\1;' contient la back-reference \1 .

'g' comme quatrième paramètre de fonction est requis pour un remplacement répété.

Lectures complémentaires :

D'autres façons de résoudre ce problème incluent un CTE récursif ou une fonction de retour d'ensemble ...

Remplir de droite à gauche

(Comme vous l'avez ajouté dans Comment mettre des valeurs en partant du côté droit dans des colonnes ? )
Comptez simplement des nombres comme :

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<>violon ici