2011-12-21 3 views
38

я имею запятую данные в столбце:Split разделенные запятыми данные столбцов в дополнительных столбцах

Column 
------- 
a,b,c,d 

Я хочу разделить запятой разделенных данных в несколько столбцов, чтобы получить этот результат:

Column1 Column2 Column3 Column4 
------- ------- ------- ------- 
a  b  c  d 

Как это можно достичь?

ответ

45

Если количество полей в CSV постоянен, то вы могли бы сделать что-то вроде этого:

select a[1], a[2], a[3], a[4] 
from (
    select regexp_split_to_array('a,b,c,d', ',') 
) as dt(a) 

Например:

=> select a[1], a[2], a[3], a[4] from (select regexp_split_to_array('a,b,c,d', ',')) as dt(a); 
a | a | a | a 
---+---+---+--- 
a | b | c | d 
(1 row) 

Если число полей в CSV не является постоянной то вы можете получить максимальное количество полей с чем-то вроде этого:

select max(array_length(regexp_split_to_array(csv, ','), 1)) 
from your_table 

, а затем b uild соответствующий список столбцов a[1], a[2], ..., a[M] для вашего запроса. Таким образом, если выше дал вам максимум 6, вы бы использовать это:

select a[1], a[2], a[3], a[4], a[5], a[6] 
from (
    select regexp_split_to_array(csv, ',') 
    from your_table 
) as dt(a) 

Вы могли бы объединить эти два запроса в функцию, если вы хотите.

Например, дать эти данные (это NULL в последней строке):

=> select * from csvs; 
    csv  
------------- 
1,2,3 
1,2,3,4 
1,2,3,4,5,6 

(4 rows) 

=> select max(array_length(regexp_split_to_array(csv, ','), 1)) from csvs; 
max 
----- 
    6 
(1 row) 

=> select a[1], a[2], a[3], a[4], a[5], a[6] from (select regexp_split_to_array(csv, ',') from csvs) as dt(a); 
a | a | a | a | a | a 
---+---+---+---+---+--- 
1 | 2 | 3 | | | 
1 | 2 | 3 | 4 | | 
1 | 2 | 3 | 4 | 5 | 6 
    | | | | | 
(4 rows) 

Поскольку ваш разделителем является простой фиксированной строкой, вы можете также использовать string_to_array вместо regexp_split_to_array:

select ... 
from (
    select string_to_array(csv, ',') 
    from csvs 
) as dt(a); 

Благодаря Michael для напоминания об этой функции.

Вы действительно должны перепроектировать схему базы данных, чтобы избежать столба CSV, если это вообще возможно. Вместо этого вы должны использовать столбец массива или отдельную таблицу.

+0

Благодаря должен проверить и восстановить – Gallop

+6

Рассмотрите возможность использования 'string_to_array' вместо' regexp_split_to_array'; он должен быть быстрее, поскольку он не имеет накладных расходов на обработку регулярных выражений. – Michael

+1

@Michael Вы могли бы добавить это как еще один ответ, если хотите. Или я мог бы добавить 'string_to_array' в качестве опции в мой, не уверенный, как я пропустил это. –

64

split_part() делает то, что вы хотите в один шаг:

SELECT split_part(col, ',', 1) AS col1 
    , split_part(col, ',', 2) AS col2 
    , split_part(col, ',', 3) AS col3 
    , split_part(col, ',', 4) AS col4 
FROM tbl; 

Добавьте столько строк, сколько у вас есть элементы в col (максимально возможного). Столбцы, превышающие элементы данных, будут пустыми строками ('').

+4

И, похоже, будет выполняться намного быстрее, чем версия regexp_split_to_array. –

+0

@ JohnBarça: Все функции регулярного выражения сравнительно дороги. Мощный, но по цене ... –

+4

Легенда! Это, безусловно, самый быстрый подход к этой проблеме. –

1

Вы можете использовать функцию разделения.

SELECT 
    (select top 1 item from dbo.Split(FullName,',') where id=1) Column1, 
    (select top 1 item from dbo.Split(FullName,',') where id=2) Column2, 
    (select top 1 item from dbo.Split(FullName,',') where id=3) Column3, 
    (select top 1 item from dbo.Split(FullName,',') where id=4) Column4, 
    FROM MyTbl 
Смежные вопросы