Det er typisk dårligt design at gemme CSV-værdier i en enkelt kolonne. Hvis det overhovedet er muligt, så brug i stedet et array eller et korrekt normaliseret design.
Mens du sidder fast i din nuværende situation ...
For kendt lille maksimalt antal elementer
En simpel løsning uden tricks eller rekursion vil gøre:
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 her
id
er PK for den oprindelige tabel.
Dette forudsætter naturligvis ', ' som separator.
Du kan nemt tilpasse.
Relateret:
For ukendt antal elementer
Forskellige måder. En måde at bruge regexp_replace()
at udskifte hver femte separator, før du tømmer ...
-- 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 her
Dette forudsætter, at den valgte separator ;
aldrig vises i dine strenge. (Ligesom ,
kan aldrig dukke op.)
Det regulære udtryksmønster er nøglen:'((?:.*?,){4}.*?),'
(?:)
... “non-capturing” sæt parenteser
()
... “fanger” sæt parenteser *?
... ikke-greedy quantifier
{4}?
... sekvens af præcis 4 kampe
Erstatningen '\1;'
indeholder tilbagehenvisningen
\1
.
'g'
som en fjerde funktionsparameter er nødvendig for gentagen udskiftning.
Yderligere læsning:
- PostgreSQL ®exp_split_unnest
- Anvend ` trim()` og `regexp_replace()` på tekstarray
- PostgreSQL unnest() med elementnummer
Andre måder at løse dette på inkluderer en rekursiv CTE eller en sæt-returnerende funktion ...
Fyld fra højre mod venstre
(Som du tilføjede i Hvordan sætter man værdier, der starter fra højre side i kolonner?
)
Du skal blot tælle tal ned som:
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 her