Przechowywanie wartości CSV w jednej kolumnie jest zazwyczaj złym projektem. Jeśli to w ogóle możliwe, użyj zamiast tego tablicy lub odpowiednio znormalizowanego projektu.
Gdy utknąłeś w swojej obecnej sytuacji...
Dla znanej małej maksymalnej liczby elementów
Wystarczy proste rozwiązanie bez sztuczek i rekurencji:
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 tutaj
id
będący PK oryginalnej tabeli.
Zakłada to oczywiście ',' jako separator.
Możesz łatwo dostosować.
Powiązane:
Dla nieznanej liczby elementów
Różne drogi. W jedną stronę użyj regexp_replace()
wymienić co piąty separator przed rozgnieżdżeniem...
-- 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 tutaj
Zakłada się, że wybrany separator ;
nigdy pojawia się w twoich strunach. (Podobnie jak ,
nigdy się nie pojawi.)
Wzorzec wyrażenia regularnego to klucz:'((?:.*?,){4}.*?),'
(?:)
... zestaw „nieprzechwytujących” nawiasów
()
... „przechwytywanie” zestawu nawiasów *?
... kwantyfikator nie zachłanny
{4}?
... sekwencja dokładnie 4 dopasowań
Zastępczy '\1;'
zawiera odniesienie wsteczne
\1
.
'g'
jako czwarty parametr funkcji jest wymagany do powtórnej wymiany.
Dalsza lektura:
- PostgreSQL i regexp_split_to_array + rozgniecenie
- Zastosuj ` trim()` i `regexp_replace()` w tablicy tekstowej
- PostgreSQL unnest() z numerem elementu
Inne sposoby rozwiązania tego problemu obejmują rekurencyjne CTE lub funkcję zwracania zestawu ...
Wypełnij od prawej do lewej
(Tak jak dodałeś w Jak umieścić wartości zaczynające się od prawej strony w kolumnach?
)
Po prostu odliczaj liczby, takie jak:
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 tutaj