将以逗号分隔的列数据拆分为其他列


71

我在列中用逗号分隔数据:

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

我想将逗号分隔的数据分成多列以获取此输出:

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

如何做到这一点?

Answers:


79

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

然后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列。您应该使用数组列或单独的表。


12
考虑使用string_to_array代替regexp_split_to_array; 它应该更快,因为它没有正则表达式处理的开销。
迈克尔

1
@Michael如果愿意,可以将其添加为另一个答案。或者我可以string_to_array在我的选项中添加一个,不确定我是怎么错过的。
亩太短

2
@DennisBauszus:很好。你也检查split_part过吗?只是好奇。
亩太短了

1
粉碎 比string_to_array快3倍。应该标记为答案。给自己的提示:必须阅读所有答案。
丹尼斯·鲍斯

1
@DennisBauszus不会这样。寻找Erwin Brandsetter或Craig Ringer在PostgreSQL问题上要说的话通常是个好主意,他们确实知道自己的东西,而且他们的答案往往相当详尽。
亩太短了

114

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(可能的最大值)。超出数据项的列将为空字符串('')。


9
而且执行速度似乎比regexp_split_to_array版本快得多。
约翰·鲍威尔

1
@JohnBarça:所有正则表达式函数都比较昂贵。功能强大,但要付出代价……
Erwin Brandstetter

8
传说!到目前为止,这是解决此类问题最快的方法。
丹尼斯·鲍斯

1
如果知道这个答案所假定的值的数量,mu的答案也是一个步骤。迈克尔的添加string_to_array使正则表达式费用无效。
juanitogan

1
@juanitogan:是的,string_to_array使正则表达式费用无效。但是对于一手充满价值的手来说,这仍然要快得多。请参阅上面
Erwin Brandstetter

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.