PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Dividir valores separados por vírgulas na tabela de destino com número fixo de colunas


Normalmente, é um design ruim armazenar valores CSV em uma única coluna. Se possível, use uma matriz ou um design devidamente normalizado.

Enquanto preso com sua situação atual ...

Para um pequeno número máximo de elementos conhecido


Uma solução simples sem truques ou recursão fará:
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 aqui

id sendo o PK da tabela original.
Isso assume ', ' como separador, obviamente.
Você pode adaptar facilmente.

Relacionado:

Para número desconhecido de elementos


Várias maneiras. Uma maneira de usar regexp_replace() para substituir cada quinto separador antes de desaninhar ...
-- 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 aqui

Isso pressupõe que o separador escolhido ; nunca aparece em suas strings. (Assim como , nunca pode aparecer.)

O padrão de expressão regular é a chave:'((?:.*?,){4}.*?),'

(?:) ... conjunto de parênteses "sem captura"
() ... “capturando” conjunto de parênteses
*? ... quantificador não-ganancioso
{4}? ... sequência de exatamente 4 partidas

A substituição '\1;' contém a back-reference \1 .

'g' como o quarto parâmetro de função é necessário para substituição repetida.

Leitura adicional:

Outras maneiras de resolver isso incluem um CTE recursivo ou uma função de retorno de conjunto ...

Preencher da direita para a esquerda


(Como você adicionou em Como colocar valores começando do lado direito em colunas? )
Basta contar números como:
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 aqui