PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Durch Komma getrennte Werte in Zieltabelle mit fester Spaltenanzahl aufteilen

Es ist normalerweise ein schlechtes Design, CSV-Werte in einer einzigen Spalte zu speichern. Verwenden Sie nach Möglichkeit stattdessen ein Array oder ein ordnungsgemäß normalisiertes Design.

Während Sie in Ihrer aktuellen Situation feststecken ...

Für bekannte kleine maximale Anzahl von Elementen

Eine einfache Lösung ohne Tricks oder Rekursion reicht aus:

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 hier

id ist die PK der Originaltabelle.
Dies setzt natürlich ', ' als Trennzeichen voraus.
Sie können es leicht anpassen.

Verwandte:

Für unbekannte Anzahl von Elementen

Verschiedene Wege. Verwenden Sie zum einen regexp_replace() um jedes fünfte Trennzeichen vor dem Aufheben der Verschachtelung zu ersetzen ...

-- 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 hier

Dies setzt voraus, dass das gewählte Trennzeichen ; nie erscheint in Ihren Saiten. (Genau wie , kann niemals erscheinen.)

Das reguläre Ausdrucksmuster ist der Schlüssel:'((?:.*?,){4}.*?),'

(?:) ... "nicht erfassender" Klammersatz
() ... "erfassender" Klammersatz
*? ... nicht-gieriger Quantifizierer
{4}? ... Folge von genau 4 Treffern

Der Ersatz '\1;' enthält die Rückreferenz \1 .

'g' als vierter Funktionsparameter wird zum wiederholten Ersetzen benötigt.

Weiterführende Literatur:

Andere Möglichkeiten, dies zu lösen, umfassen einen rekursiven CTE oder eine Set-Returning-Funktion ...

Von rechts nach links füllen

(Wie Sie in Wie setze ich Werte beginnend von der rechten Seite in Spalten? hinzugefügt )
Zählen Sie einfach Zahlen herunter wie:

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 hier