PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Разделете стойности, разделени със запетая, в целева таблица с фиксиран брой колони

Обикновено е лош дизайн да се съхраняват CSV стойности в една колона. Ако изобщо е възможно, вместо това използвайте масив или правилно нормализиран дизайн.

Докато сте в текущата си ситуация...

За известен малък максимален брой елементи

Едно просто решение без хитрост или рекурсия ще свърши работа:

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 тук

id като PK на оригиналната таблица.
Това очевидно предполага ', ' като разделител.
Можете да се адаптирате лесно.

Свързани:

За неизвестен брой елементи

Различни начини. Един начин използвайте regexp_replace() за замяна на всеки пети разделител преди разместване ...

-- 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 тук

Това предполага, че избраният разделител ; никога се появява във вашите низове. (Точно като , никога не може да се появи.)

Моделът на регулярния израз е ключът:'((?:.*?,){4}.*?),'

(?:) ... "неприхващащ" набор от скоби
() ... „улавяне“ на набор от скоби
*? ... неалчен квантификатор
{4}? ... поредица от точно 4 съвпадения

Замяната '\1;' съдържа обратна препратка \1 .

'g' като четвърти функционален параметър е необходим за многократна подмяна.

Допълнителна информация:

Други начини за решаване на това включват рекурсивен CTE или функция за връщане на набор ...

Попълнете отдясно наляво

(Както добавихте в Как да поставяте стойности, започващи от дясната страна, в колони? )
Просто отброявайте числа като:

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 тук



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Попълнете липсващите редове при агрегиране върху множество полета в Postgres

  2. Създаване на временни таблици в SQL

  3. Postgres - Как да конвертирате ред с int диапазон в междинни редове от отделни стойности от този диапазон?

  4. org.postgresql.util.PSQLException:Индексът на колоната е извън диапазона:3, брой колони:2

  5. Защо setval() се проваля с връзка ... не съществува?