pgsql使用积累系列_pg存储过程(函数)创建(以手机号校验为例)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wfl_137724/article/details/86064361

      pg数据库里面没有地道的存储过程(procudure),取而代之的是函数。函数的编写支持多种语言,底层的库函数通常是用C语言编写的,应用级别函数可用sql和pgsql。

下面通过一个通用的手机号清洗的函数,来展示一个函数的级别要素,通用函数构造方案,及postgresql中正则表达式的使用和拼接包含字符串的字符串方法。整个函数的功能,就是通过传入的表名,表主键及需要清洗的手机号字段,将不符合要求的的手机号洗为空字符串,之所以不洗成null,是因为null在有些情况下会给人造成困扰(比如selece带条件比较时数据跟预期不一致),该函数只能解决小写的参数。下面详解

CREATE OR REPLACE FUNCTION "public"."check_phone"("table_name" varchar, "table_id" varchar, "phone" varchar)
  RETURNS "pg_catalog"."void" AS $BODY$

DECLARE
    exec_str VARCHAR(1024);

BEGIN
	RAISE NOTICE 'notice: %', 'begin check';
	exec_str = 'create temp table temp_phone on commit drop as
	select ' || table_id || ',' || '
		case when ' || phone || E' ~ \'^[+]\' then replace(' || phone || E', \'+\', \'00\') else ' || phone || ' end as ' || phone || '
	from ' || table_name || ';' || '

	create temp table temp_phone_1 on commit drop as
	select ' || table_id || ',' || '
		case when ' || phone || E' ~ \'\\D\' then \'\'
			when ' || phone || E' is null then \'\'
			when ' || phone || E' ~ \'^1\' and length(' || phone || ') = 11 then ' || phone || '
			when ' || phone || E'~ \'^01\' and length(' || phone || ') = 12 then ' || phone || '
			when ' || phone || E'~ \'^861\' and length(' || phone || ') = 13 then ' || phone || '
			when ' || phone || E'~ \'00861\' and length(' || phone || ') = 15 then ' || phone || E'
		else \'\' end as ' || phone || '
	from temp_phone;

	update ' || table_name || '  a set ' || phone || ' = t.' || phone || '
	from (select ' || table_id || ', ' || phone || ' from temp_phone_1) t
	where a.' || table_id || ' = t.' || table_id || ';';

	RAISE NOTICE 'notice: %', exec_str;
	execute exec_str;
END;

$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100

CREATE OR REPLACE FUNCTION "public"."check_phone"():在指定的模式下创建一个函数名为check_phone的函数,如果函数已经存在就更新它。

"table_name" varchar, "table_id" varchar, "phone" varchar :函数的参数,默认是in (函数的参数分为in,out,inout,这个大部分关系型数据库都一样)。

RETURNS "pg_catalog"."void":返回类型,在postgres里,一切皆对象,类型和表一样可以自定义,也有对应的模式。

AS :表示下面的内容等价于前面的定义。可以理解成上面是定义,下面是实现。

$BODY$:函数的主题。可以理解成html页面里的body,是实际功能的载体。

DECLARE exec_str VARCHAR(1024) :申明一个待执行的sql字符串。

BEGIN...END:其中的内容在一个事务内。其实有的存储过程不加这个也是可以的,只是多个语句不会在一个事务内执行。

RAISE NOTICE 'notice: %', 'begin check':打印日志,%是占位符。

create temp table temp_phone on commit drop as :创建临时表,并在事务提交时自动删除,as跟上面的AS是一个意思。

E' ~ \'^[+]\' then replace(':E使字符串内的转义字符'\'生效。~ 代表正则表达式,匹配字符串中首字母是'+'的字符串。

E' ~ \'\\D\' then \'\':'\D'匹配一个非数字。

execute exec_str:执行sql串

 LANGUAGE plpgsql:表示用的是pgsql语言。

VOLATILE:表示函数操作对象为最大,即可以操作表,数据库等等。这个是默认值,无需可以配置。如果控制存储过程的使用范围需要调整这个值。

COST 100:这个参数会影响执行计划。也是默认值,不建议修改。

因为postgresql字段区分大小写,而且查询时会将大写字段默认改成小写,如果数据库字段为大写,则会出现找不到字段的错误,所以建议表结构最好用小写,多个单词用下划线连接,而不是用驼峰结构。当然也不是完全解决不了大小写问题的,可以在字段或者表等元素前后加上"号来阻止大写自动转为小写。

下面提供一个同样功能但是能适配大写字段名,表名的函数代码,除了支持大写的情况,这段代码还展示了另一种处理字符拼接中包含字符串的问题,上段代码是通过正则匹配解决,这段代码是通过在原有字符串外再套一层单引号(')解决的。

CREATE OR REPLACE FUNCTION "public"."check_phone"("table_name" varchar, "table_id" varchar, "phone" varchar)
  RETURNS "pg_catalog"."void" AS $BODY$


DECLARE
    exec_str VARCHAR(1024);

BEGIN
	RAISE NOTICE 'notice: %', 'begin check';
	exec_str = 'create temp table temp_phone on commit drop as
	select "' || table_id || '",' || '
		case when "' || phone || '" ~ ''^[+]'' then replace("' || phone || '", ''+'', ''00'') else "' || phone || '" end as "' || phone || '"
	from "' || table_name || '";' || '

	create temp table temp_phone_1 on commit drop as
	select "' || table_id || '",' || '
		case when "' || phone || '" ~ ''\D'' then ''''
			when "' || phone || '" is null then ''''
			when "' || phone || '" ~ ''^1'' and length("' || phone || '") = 11 then "' || phone || '"
			when "' || phone || '" ~ ''^01'' and length("' || phone || '") = 12 then "' || phone || '"
			when "' || phone || '" ~ ''^861'' and length("' || phone || '") = 13 then "' || phone || '"
			when "' || phone || '" ~ ''00861'' and length("' || phone || '") = 15 then "' || phone || '"
		else '''' end as "' || phone || '"
	from temp_phone;

	update "' || table_name || '"  a set "' || phone || '" = t."' || phone || '"
	from (select "' || table_id || '", "' || phone || '" from temp_phone_1) t
	where a."' || table_id || '" = t."' || table_id || '";';

	RAISE NOTICE 'notice: %', exec_str;
	execute exec_str;
END;


$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100

猜你喜欢

转载自blog.csdn.net/wfl_137724/article/details/86064361
今日推荐