PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Dividi i valori separati da virgole nella tabella di destinazione con un numero fisso di colonne

In genere è una cattiva progettazione archiviare i valori CSV in una singola colonna. Se possibile, usa invece un array o un design adeguatamente normalizzato.

Mentre sei bloccato con la tua situazione attuale ...

Per un numero massimo di elementi noto piccolo

Una soluzione semplice senza inganno o ricorsione andrà bene:

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<>violino qui

id essendo il PK della tabella originale.
Questo presuppone ',' come separatore, ovviamente.
Puoi adattarti facilmente.

Correlati:

Per numero sconosciuto di elementi

Vari modi. Uso unidirezionale regexp_replace() sostituire ogni quinto separatore prima di disnidare...

-- 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<>violino qui

Ciò presuppone che il separatore scelto ; mai appare nelle tue stringhe. (Proprio come , non può mai apparire.)

Il modello di espressione regolare è la chiave:'((?:.*?,){4}.*?),'

(?:) ... Set di parentesi "non catturanti"
() ... insieme di parentesi "cattura"
*? ... quantificatore non avido
{4}? ... sequenza di esattamente 4 corrispondenze

La sostituzione '\1;' contiene il back-reference \1 .

'g' poiché il quarto parametro di funzione è richiesto per la sostituzione ripetuta.

Ulteriori letture:

Altri modi per risolvere questo problema includono un CTE ricorsivo o una funzione di ritorno di set ...

Riempi da destra a sinistra

(Come hai aggiunto in Come inserire i valori a partire dal lato destro nelle colonne? )
Conta semplicemente alla rovescia numeri come:

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<>violino qui