从PostgreSQL中的非标准标记字符串中提取值

时间:2014-01-06 11:32:55

标签: postgresql

不幸的是,我有一个如下表:

DROP TABLE IF EXISTS my_list;
CREATE TABLE my_list (index int PRIMARY KEY, mystring text, status text);

INSERT INTO my_list    
(index, mystring,                                           status) VALUES 
   (12, '',                                                    'D'), 
   (14, '[id] 5',                                              'A'), 
   (15, '[id] 12[num] 03952145815',                            'C'), 
   (16, '[id] 314[num] 03952145815[name] Sweet',               'E'), 
   (19, '[id] 01211[num] 03952145815[name] Home[oth] Alabama', 'B'); 

是否有任何技巧可以从上面显示的[id]文字中获取integer mystring的数量?好像我运行了以下查询:

SELECT index, extract_id_function(mystring), status FROM my_list;

得到的结果如下:

12  0     D  
14  5     A 
15  12    C 
16  314   E 
19  1211  B 

最好只使用简单的字符串函数,如果不是正则表达式就可以了。

1 个答案:

答案 0 :(得分:2)

如果我理解正确,你有一种非常规的标记格式,其中[id]后跟一个空格,然后是一系列代表数字标识符的数字。没有结束标记,下一个非数字字段结束ID。

如果是这样,你将能够使用非正则表达式字符串操作,但只能非常糟糕。你真正需要的是strtol的SQL等价物,它消耗输入到第一个非数字并且只返回它。对integer的强制转换不会这样做,如果在数字后面看到非数字垃圾,它会报告错误。 (碰巧我刚刚写了一个C扩展,公开strtol来解码十六进制值,但我猜你不想使用C扩展,如果你甚至不想要正则表达式...)

如果您做出简化假设,[id] nnnn标记总是字符串结尾结尾,则可以使用字符串操作完成标记,因此数字末尾始终为[。我们还假设您只对第一个[id]感兴趣,如果多个字符串出现在字符串中。这样你就可以写出类似下面可怕的怪物:

select
  "index",
  case 
    when next_tag_idx > 0 then substring(cut_id from 0 for next_tag_idx) 
    else cut_id 
  end AS "my_id",
  "status"
from (
  select 
    position('[' in cut_id) AS next_tag_idx,
    *
  from (
    select 
      case 
        when id_offset = 0 then null 
        else substring(mystring from id_offset + 4) 
      end AS cut_id,
      *
    from (
      select
        position('[id] ' in mystring) AS id_offset,
        *
      from my_list
    ) x
  ) y
) z;

如果有人真的将这个查询用于任何事情,小猫会从天而降,趴在人行道上,一直惊恐地哭泣)。

或者您可以理智并且只使用正则表达式进行此类字符串处理,在这种情况下,您的查询(假设您只想要第一个[id])是:

regress=> SELECT
            "index", 
            coalesce((SELECT (regexp_matches(mystring, '\[id\]\s?(\d+)'))[1])::integer, 0) AS my_id,
            status 
          FROM my_list;
 index | my_id          | status 
-------+----------------+--------
    12 | 0              | D
    14 | 5              | A
    15 | 12             | C
    16 | 314            | E
    19 | 01211          | B
(5 rows)

更新:如果您在regex中遇到unicode处理问题,请升级到Pg 9.2。见https://stackoverflow.com/a/14293924/398670