CASE with regexp:"在上下文中调用的集值函数,不能接受集合"

pst*_*ton 3 regex postgresql postgresql-9.0 set-returning-functions

我试图在PostgreSQL 9.0.1中进行稍微复杂的字符串转换.值中my_col的长字符串格式为:

'12345_sometext_X12B_1'
'12345_sometext_optionaltext_Y09B_1'
'12345_sometext_optionaltext_X12A_1'
Run Code Online (Sandbox Code Playgroud)

我需要将'X12'部分转换为已知的数值,有几个不同的已知值(最多5个).

我希望能够在一个查询中确定这一点,而不需要子查询.但是,以下内容对我不起作用.最后一列是抛出异常的那一列.CASE由于某种原因,我似乎无法使用这些函数的输出结合语句.我列出了进行中的列仅用于演示目的.

select
          regexp_matches(my_col, E'^.*_([^_]*)[A-Z]{1}_\\d*$'), -- returns {'X12'}
         (regexp_matches(my_col, E'^.*_([^_]*)[A-Z]{1}_\\d*$'))[1], -- returns 'X12'
    case (regexp_matches(my_col, E'^.*_([^_]*)[A-Z]{1}_\\d*$'))[1]
        when 'X12' then '1200'
        when 'Y09' then '950'
        else '?' end -- should return '1200' but throws error
from my_table;
Run Code Online (Sandbox Code Playgroud)

相反,我收到错误:

ERROR: set-valued function called in context that cannot accept a set
SQL state: 0A000
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我吗?

Cra*_*ger 8

鉴于数据:

create table my_table(my_col text);
insert into my_table(my_col) values
('12345_sometext_X12B_1'),
('12345_sometext_optionaltext_Y09B_1'),
('12345_sometext_optionaltext_X12A_1'),
('nomatch');
Run Code Online (Sandbox Code Playgroud)

上述查询确实会产生您报告的错误.非常奇怪,因为:

SELECT pg_typeof((regexp_matches(my_col, E'^.*_([^_]*)[A-Z]{1}_\\d*$'))[1]);
Run Code Online (Sandbox Code Playgroud)

返回'文字'.它应该说,setof text但这是陷阱:regex_matches是一个集合返回功能.当在PostgreSQL中的FROM子句之外调用时,那些...有趣...行为.

模式匹配:

regexp_matches函数返回由匹配POSIX正则表达式模式产生的所有捕获的子字符串的文本数组.它具有语法regexp_matches(string,pattern [,flags]).该函数不能返回任何行,一行或多行

尝试重新构造查询以使用子查询来调用SRF.如果匹配器返回多行,则会失败:

SELECT 
  CASE (SELECT x[1] FROM regexp_matches(my_col, E'^.*_([^_]*)[A-Z]{1}_\\d*$') x)
    WHEN 'X12' THEN '1200'
    WHEN 'Y09' THEN '950'
    ELSE '?'
  END
FROM my_table;
Run Code Online (Sandbox Code Playgroud)

想看看SELECT中有多奇怪的SRF在Pg中?比较这些查询的结果:

SELECT generate_series(1,10), generate_series(1,15);
Run Code Online (Sandbox Code Playgroud)

和:

SELECT generate_series(1,10), generate_series(1,20);
Run Code Online (Sandbox Code Playgroud)

1号产生30排.第二个产生20.有趣解释原因.如果偶尔有用的结果,Pg中SELECT列表中的多个SRF会产生疯狂.

LATERAL由于Tom Lane提供了一个理智且定义明确的替代方案,PostgreSQL 9.3支持SQL标准子句.