【问题标题】:PostgreSQL & regexp_split_to_array + unnestPostgreSQL & regexp_split_to_array + unnest
【发布时间】:2013-03-27 15:56:11
【问题描述】:

我有那种字符串

测试 1|纽约| X,测试 2|芝加哥|Y,测试 3|宾夕法尼亚哈里斯堡| Z

我需要的结果是

 Column1  Column 2     Column3
 Test 1   new york        X
 Test 2   chicago         Y
 Test 3   harrisburg,pa   Z

但是运行这个查询

SELECT  
split_part(stat.st, '|', 1) Column1,
split_part(stat.st, '|', 2) Column2,    
split_part(stat.st, '|', 3) Column3
FROM
(
    SELECT
            UNNEST (
                string_to_array('Test 1|new york| X, Test 2| chicago|Y, Test 3| harrisburg, pa| Z',',')
            )
         AS st
) stat;

结果是

 Column1  Column 2   Column3
 Test 1   new york      X
 Test 2   chicago       Y
 Test 3   harrisburg    
 pa          Z  

Column3 可以是所有内容(| 除外)。匹配它的可能模式。这可以重复 N 次。 STRING 可以是除 | 之外的所有内容字符。

我如何使用regexp_split_to_array() 来设置我想要的结果集?

【问题讨论】:

  • 您没有提供足够的信息。 column3 总是一个大写字符吗?你还能告诉 uas 什么?
  • 没有 Column3 可以是一切(除了 | )。匹配它的可能模式是 。这可以重复 N 次。 STRING 可以是除 | 之外的所有内容字符。
  • 这类信息必须在问题中。请编辑。

标签: sql regex postgresql postgresql-9.1 crosstab


【解决方案1】:

几乎没有足够的信息来完成这项工作。但这确实有效:

SELECT * FROM crosstab3(
   $$
   SELECT (rn/3)::text AS x, (rn%3)::text, item
   FROM  (
      SELECT row_number() OVER () - 1 AS rn, trim(item) AS item
      FROM (
         SELECT CASE WHEN rn%2 = 1 THEN regexp_split_to_table(item, ',') 
                     ELSE item END AS item
         FROM  (
            SELECT row_number() OVER () AS rn, *
            FROM regexp_split_to_table('Test 1|new york| X, Test 2| chicago|Y, Test 3| harrisburg, pa| Z', '\|') AS item
            ) x
         ) y
      ) z
   $$)

返回:

 row_name | category_1 |   category_2   | category_3
----------+------------+----------------+------------
 0        | Test 1     | new york       | X
 1        | Test 2     | chicago        | Y
 2        | Test 3     | harrisburg, pa | Z

| 处拆分字符串后,我建立在只有具有不均匀行号 的行才能在, 处拆分的标准。
trim() 结果并添加另一个row_number() 的导数以在进行交叉制表之前达到此中间状态:

 x | text |      item
---+------+----------------
 0 | 0    | Test 1
 0 | 1    | new york
 0 | 2    | X
 1 | 0    | Test 2
 1 | 1    | chicago
 1 | 2    | Y
 2 | 0    | Test 3
 2 | 1    | harrisburg, pa
 2 | 2    | Z

最后,我应用了tablefunc 模块中的crosstab3() 函数。要安装它,如果您还没有:

CREATE EXTENSION tablefunc;

使用regexp_replace() 进行预处理

这里有一个更容易理解的替代方案。不确定哪个更快。复杂的正则表达式往往很昂贵:

SELECT trim(split_part(a,'|', 1)) AS column1
      ,trim(split_part(a,'|', 2)) AS column2
      ,trim(split_part(a,'|', 3)) AS column3
FROM  (
   SELECT unnest(
             string_to_array(
                         regexp_replace('Test 1|new york| X, Test 2| chicago|Y, Test 3| harrisburg, pa| Z'
                        ,'([^|]*\|[^|]*\|[^,]*),', '\1~^~', 'g'), '~^~')) AS a
   ) sub

这仅在两个管道 (|) 之后替换逗号 (,),然后再继续。
现在使用 * 而不是 + 来允许管道之间的空字符串。

【讨论】:

  • 请检查您的答案。我试过了,但结果不一样。
     0 T e s 1 t 1 2 | n e 3 w y 4 或 r k 5 | X 6 7 T e s 8 t 2 9 | c 10 h i c 11 a g o 12 | Y , 13 T e 14 s t 15 3 | 16 h a r 17 r i s 18 b u r 19 g , 20 p a | 21 Z 
  • @LuigiSaggese:我在发布之前已经使用 PostgreSQL 9.1 进行了测试。我可以重现我的结果。您可能需要设置 standard_conforming_strings = on - 在 9.1 中默认启用。
  • @LuigiSaggese:这是一种…… ;)
  • 最后的解决方案太棒了!你能不能“修复”它,比如'||,'或'Magic||' ?
  • @LuigiSaggese:我相信我现在做到了。
猜你喜欢
  • 1970-01-01
  • 2020-04-28
  • 2015-02-06
  • 2023-03-10
  • 1970-01-01
  • 2012-02-04
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多