【问题标题】:Split comma separated column data into additional columns将逗号分隔的列数据拆分为其他列
【发布时间】:2012-01-24 23:29:00
【问题描述】:

我在一列中有逗号分隔的数据:

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

我想将逗号分隔的数据拆分成多列来得到这个输出:

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

如何做到这一点?

【问题讨论】:

    标签: postgresql split delimiter postgresql-8.4


    【解决方案1】:

    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 中的项目一样多的行(可能的最大值)。
    超出数据项的列将是空字符串 ('')。

    【讨论】:

    • 而且执行起来似乎比 regexp_split_to_array 版本快很多。
    • @JohnBarça:所有正则表达式函数都比较昂贵。功能强大,但要付出代价......
    • 传奇!这是迄今为止解决此类问题的最快方法。
    • mu 的答案也是一个步骤,如果值的数量是已知的,例如这个答案假设的。 Michael 添加的string_to_array 使正则表达式费用无效。
    • @juanitogan:是的,string_to_array 使正则表达式费用无效。但是对于一手充满价值的牌来说,这仍然要快得多。见comment with feedback above.
    【解决方案2】:

    如果 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 列。您应该改用数组列或单独的表。

    【讨论】:

    • 考虑使用string_to_array而不是regexp_split_to_array;它应该更快,因为它没有正则表达式处理的开销。
    • @Michael 如果您愿意,可以将其添加为另一个答案。或者我可以添加string_to_array 作为我的选项,不知道我是怎么错过的。
    • @DennisBauszus:很好。你也检查了split_part 吗?只是好奇。
    • 粉碎。比 string_to_array 快 3 倍。应标记为答案。提醒自己:必须阅读所有答案。
    • @DennisBauszus 不会反对。看看 Erwin Brandsetter 或 Craig Ringer 对 PostgreSQL 问题的看法通常是个好主意,他们真的很了解自己的知识,而且他们的答案往往相当透彻。
    【解决方案3】:

    您可以使用拆分功能。

        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
    

    【讨论】:

    • 问题指的是 PostgreSQL - 那是 SQL Server 语法?
    猜你喜欢
    • 2023-03-21
    • 2018-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 2018-11-02
    • 2018-09-25
    相关资源
    最近更新 更多