sql >> Database >  >> RDS >> PostgreSQL

Door komma's gescheiden waarden splitsen in doeltabel met een vast aantal kolommen

Het is meestal een slecht ontwerp om CSV-waarden in één kolom op te slaan. Gebruik in plaats daarvan indien mogelijk een array of een correct genormaliseerd ontwerp.

Terwijl je vastzit in je huidige situatie ...

Voor bekend klein maximum aantal elementen

Een eenvoudige oplossing zonder bedrog of recursie is voldoende:

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 zijnde de PK van de originele tabel.
Dit veronderstelt natuurlijk ', ' als scheidingsteken.
Je kunt het gemakkelijk aanpassen.

Gerelateerd:

Voor onbekend aantal elementen

Verschillende manieren. Gebruik in één richting regexp_replace() om elke vijfde scheidingsteken te vervangen voordat u de nesten verwijdert ...

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

Dit veronderstelt dat het gekozen scheidingsteken ; nooit verschijnt in uw tekenreeksen. (Net als , kan nooit verschijnen.)

Het patroon van de reguliere expressie is de sleutel:'((?:.*?,){4}.*?),'

(?:) ... "niet-vastleggende" set haakjes
() ... "vastleggen" set haakjes
*? ...
niet-gulzige kwantor
{4}? ... reeks van precies 4 overeenkomsten

De vervanging '\1;' bevat de terugverwijzing \1 .

'g' als vierde functieparameter is vereist voor herhaalde vervanging.

Verder lezen:

Andere manieren om dit op te lossen zijn een recursieve CTE of een set-retourfunctie ...

Vul van rechts naar links

(Zoals je hebt toegevoegd in Hoe zet je waarden vanaf de rechterkant in kolommen? )
Tel gewoon getallen af ​​zoals:

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



  1. ORA-00947:Niet genoeg waarden

  2. XML versnipperen van uitvoeringsplannen

  3. Fout (ORA-21700) met tabeloperator na update naar Oracle 12.2 vanaf 12.1

  4. Een IF-statement gebruiken in een MySQL SELECT-query