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

Opdel kommaseparerede værdier i måltabel med et fast antal kolonner

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:

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



  1. Sådan indstilles det aktuelle sprog i SQL Server (T-SQL)

  2. Bruger GROUP_CONCAT på underforespørgsel i MySQL

  3. ECONNREFUSED for Postgres på nodeJS med dockers

  4. Kryptere adgangskode før lagring i database?