2011-12-21 90 views

回答

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为您的查询找到相应的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 2011-12-21 11:05:20

+6

考虑使用'string_to_array',而不是'regexp_split_to_array';它应该更快,因为它没有正则表达式处理的开销。 – Michael 2014-09-15 06:46:18

+1

@Michael如果你愿意,你可以添加它作为另一个答案。或者我可以添加'string_to_array'作为我的选项,不知道我是如何错过的。 – 2014-09-16 04:53:24

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版本执行速度快得多。 – 2014-04-01 10:05:28

+0

@JohnBarça:所有正则表达式函数都比较昂贵。强大的,但价格... – 2014-04-01 14:31:27

+4

传说!这是迄今为止这种问题最快的方法。 – 2016-03-16 14:14:38

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