不幸的是,我有一个如下表:
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
最好只使用简单的字符串函数,如果不是正则表达式就可以了。
答案 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