PostgreSQL中regexp_matches正向预查正则报错问题求助
我之前也碰到过一模一样的坑,你遇到的报错根源其实很清晰:PostgreSQL采用的是POSIX扩展正则表达式(ERE)引擎,它不支持正向肯定预查(也就是你用的(?<=...)语法),而regex101默认用的是PCRE(Perl兼容正则)引擎,所以测试工具里能正常跑的正则,放到PostgreSQL里就会抛出ERROR: invalid regular expression: quantifier operand invalid的错误。
针对你的核心需求——仅提取(OCoLC)之后的6位及以上数字,其余情况保留原内容,我给你两个更精准的解决方案:
方案1:用捕获组替代正向预查(适配你的完整需求)
既然不能用预查,我们可以把(OCoLC)作为匹配的一部分,通过捕获组专门锁定后面的目标数字,这样比你原来的CASE语句更精准(能避免误匹配字段里其他无关的长数字):
SELECT CASE WHEN v.field_content ~* '\(ocolc\)[0-9]{6,}' THEN (regexp_matches(v.field_content, '\(ocolc\)([0-9]{6,})', 'i'))[1] ELSE v.field_content END FROM varfield as v;
这里的\(ocolc\)([0-9]{6,})会先匹配(OCoLC)开头的片段,再用()把后面的数字捕获成独立分组,最后通过[1]取出这个分组的内容。'i'参数用来忽略大小写,和你原来的'gi'里的i作用一致(PostgreSQL的regexp_matches默认只匹配一次,所以g参数在这里可以省略)。
方案2:简化查询(仅需匹配到的数字时用)
如果你的场景只需要提取包含(OCoLC)的记录对应的数字,可以直接用WHERE过滤后提取捕获组:
SELECT (regexp_matches(v.field_content, '\(ocolc\)([0-9]{6,})', 'i'))[1] AS ocolc_number FROM varfield as v WHERE v.field_content ~* '\(ocolc\)[0-9]{6,}' LIMIT 1;
另外提个小细节:你原来的替代CASE语句有个潜在问题——regexp_matches('[0-9]{6,}', 'gi')会匹配字段里任意位置的6位以上数字,而不是严格(OCoLC)之后的,要是字段里还有其他长数字,就会提取错误内容,用上面的捕获组写法就能完美规避这个问题。
内容的提问来源于stack exchange,提问作者ray_voelker

