如何在postgres中创建一个函数,用一系列' REGEXP_REPLACE&s进行更新字段

时间:2018-04-17 14:57:47

标签: postgresql plpgsql

我试图创建一个使文本列均匀化的函数。在函数的情况下,它是一系列regex_replaces。

我相信以下(缩短的)代码应该给我解决方案:

CREATE OR REPLACE FUNCTION clean_data(address_token text) RETURNS 
setof text
AS
$$
BEGIN
return case when address_token like '%allee' OR address_token LIKE '%ally' OR address_token LIKE '%aly' then regexp_replace(address_token,'(allee|ally|aly)$', 'alley')
when address_token like '%annex' OR address_token LIKE '%annx' OR address_token LIKE '%anx' then regexp_replace(address_token,'(annex$|annx$|anx$)', 'anex')
when address_token like '%arc' then regexp_replace(address_token ,'arc$', 'arcade')

.
.
.

when address_token like '%wls' then regexp_replace(address_token ,'wls$', 'wells') else address_token;
END;
$$ LANGUAGE plpgsql;

CREATE TABLE newtable AS
select postcode, (clean_data(address1)) as address1 (clean_data(address2)) as address2, (clean_data(address3)) as address3
from oldtable where postcode SIMILAR TO '(a|b)%';

但是当我运行它时,我收到错误消息:

RETURN cannot have a parameter in function returning set
LINE 5:   return case when address_token like '%allee' OR address_to...
             ^
HINT:  Use RETURN NEXT or RETURN QUERY.

当我接受其建议并使用' RETURN QUERY'相反,我告诉:

syntax error at or near "case"
LINE 5:   return query case when address_token like '%allee' OR addr...

我找不到很有帮助。

编写此函数的正确方法是什么?

我对SQL函数比较新,并且我不是100%肯定:

  • '返回文字集':这是否会按预期返回字段?
  • 语言:是这个SQL还是plpgsql
  • ' RETURN" vs' RETURN NEXT' vs'返回查询':我不确定这里的区别

过去几个小时我一直在谷歌搜索,进展甚微,获得的理解很少,所以任何帮助都会受到赞赏

3 个答案:

答案 0 :(得分:1)

关键错误是setof返回多行数据:你的函数一次只能操作一行,所以应该只返回text。您已将此标记为plpgsql,但由于它只有一个语句,因此它与SQL一样好用:SQL中不需要BEGINEND语句,而您将select而不是return结果。虽然您的CASE语句很长,但这仍然是一个简单的函数,其中一个输入和一个输出为in the docs

第二个错误是您错过了END语句的CASE:您需要结束案例,然后结束plpgsql函数,这样您就会有双端。

CREATE OR REPLACE FUNCTION clean_data(address_token text) RETURNS text
AS
$$
BEGIN
return case when address_token like '%allee' OR address_token LIKE '%ally' OR address_token LIKE '%aly' then regexp_replace(address_token,'(allee|ally|aly)$', 'alley')
.
.
.
when address_token like '%wls' then regexp_replace(address_token ,'wls$', 'wells') else address_token
end;
END;
$$ LANGUAGE plpgsql;

答案 1 :(得分:0)

PostgreSQL手册说:

  

可以声明SQL函数返回一个集合(即多行)   通过将函数的返回类型指定为SETOF sometype,或   等效地将其声明为RETURNS TABLE(列)

因此,您使用setof返回rows。在您的情况下,您将返回一个'字段'。所以你应该将你的回报改为RETURNS TEXT(没有setof),或者如果你需要一个表,你应该将你的案例输出设置成一个记录或行。

答案 2 :(得分:0)

为什么要干扰案例表达。只需按原样使用你的regexp_replace函数,它们已经在你的case语句中体现了谓词。

更好的是将表达式放入表中并循环遍历它们:

SQL Fiddle

PostgreSQL 9.3架构设置

MAILCHIMP_V3_API_URL/campaigns

查询1

create table samples(address_token text);
create table replacements(exp varchar(30), value varchar(30), flags varchar(10));

INSERT INTO samples
    (address_token)
VALUES
    ('DB Ally'),
    ('SQL Annex'),
    ('Penny Arc'),
    ('CPU Wls')
;

INSERT INTO replacements
    (exp, value, flags)
VALUES
    ('(allee|ally|aly)$', 'alley', 'i'),
    ('(annex$|annx$|anx$)', 'anex', 'i'),
    ('arc$', 'arcade', 'i'),
    ('wls$', 'wells', 'i')
;

create or replace function clean_data(address_token text) returns text
as
$$
DECLARE
  r record;
  result text;
BEGIN
  result := address_token;
  for r in (select exp, value, flags from replacements) loop
      result := regexp_replace(result, r.exp, r.value, r.flags);
  end loop;
  return result;
end;
$$ LANGUAGE plpgsql;
/

<强> Results

select * from replacements

查询2

|                 exp |  value | flags |
|---------------------|--------|-------|
|   (allee|ally|aly)$ |  alley |     i |
| (annex$|annx$|anx$) |   anex |     i |
|                arc$ | arcade |     i |
|                wls$ |  wells |     i |

<强> Results

select address_token, clean_data(address_token) new_val
  from samples