POSTGRESQL 存储过程--如何写出新版本PG的存储过程的小案例

483a83e0b05445164dcb71df4f9b4687.png

随着问问题的同学越来越多,公众号内部私信回答问题已经很困难了,所以建立了一个群,关于各种数据库的问题都可以,目前主要是 POSTGRESQL, MYSQL ,MONGODB ,POLARDB ,REDIS,SQL SERVER 等,期待你的加入,加群请添加微信liuaustin3.  (群里有各方面的工作人员和专家)

最近在开始研究POSTGRESQL 的存储过程,主要的原因有以下几个

1 因为要开发适合目前公司中的基于POSTGRESQL 的运行维护产品,同时基于POSTGRESQL 的数据库有云数据库,基于程序的安全性和部署的便利性,一部分维护的程序应该以存储过程的方式,被部署在数据库中,方便外部程序调用。

2  基于POSTGRESQL 大部分的存储过程的教学内容还是在create function部分 ,在POSTGRESQL  11 后的版本的数据库的存储过程已经不再使用create function,而采用 create procedure 的方式撰写,功能和扩展性提高了

所以需要针对POSTGRESQL 的存储过程进行一个详细的研究,看看怎么更好的为以后的工作服务。

CREATE [ OR REPLACE ] PROCEDURE
    name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
  { LANGUAGE lang_name
    | TRANSFORM { FOR TYPE type_name } [, ... ]
    | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
    | SET configuration_parameter { TO value | = value | FROM CURRENT }
    | AS 'definition'
    | AS 'obj_file', 'link_symbol'
    | sql_body

} ...

这是官方的procedure 的固定语法这里需要注意第一个地方

1  POSTGRESQL 的存储过程和函数可以是一个名字,只要后面的给定的参数不一致即可,也就是有一部分可能性存储过程和函数的名字是一样的。但我们强烈建议不要这样做。

2   存储过程中的 argmode 部分可以选择的参数有 in ,out, inout 或者  variadic 默认是in, 后面我们通过一些案例来看看如何进行这些模式的使用。

3  argname  argtype  这是存储过程中的参数名和参数的类型设置的

4  SECURITY INVOKER 为设置执行存储过程的用户的权限来调用存储过程

案例  1  

c15d4e8d6b3c1df34d36216d17a9f4a1.png


create or replace procedure dba_insert_data("id" int,"name" varchar(20))
language sql
as $$
insert into public.insert_d (id,name) values ("id","name");
$$;


call dba_insert_data(1,'pop');

select * from insert_d;

存储过程中将参数输入的部分,很简单,默认就是输入,将输入的参数和参数的类型标注即可,并且注意参数用双引号标志即可。

案例2

带有输出参数的信息和如何将信息展示在存储过程运行期间,如何将输入的参数在进行输出

4b70c453d5dfac4b15f417d2ec6c8726.png

create or replace procedure dba_insert_data("id" int,"name" varchar(20),INOUT msg text)
language plpgsql
as $$
BEGIN
insert into public.insert_d (id,name) values ("id","name");

RAISE NOTICE 'insert data process is done:%',msg;
END;
$$;


call dba_insert_data(1,'pop');

这里语法 RAISE NOTICE 是输出消息的语句 ,而通过百分号 % 来代表输入变量,然后在输出时标名变量即可。

案例 3

将存储过程中的表的字段值输出到存储过程的外部,这就需要在定义存储过程中先定义这个表的这个字段。

create or replace procedure dba_insert_data("id_in" int,"name" varchar(20))
language plpgsql
as $$

declare exid "insert_d"."id"%type;

BEGIN
insert into public.insert_d (id,name) values ("id_in","name");

select id into exid from public.insert_d ;

RAISE NOTICE 'insert data id is:%',exid;

END;
$$;

truncate table insert_d;

call dba_insert_data(1,'pop');

199ed6e5f49a26ab2d2c4fc527fb87d2.png

在这个案例中,我们定义了接受表中字段值的变量 exid ,同时将这个值输出到 message中。这里需要注意几个地方

1  请不要将变量名和字段名一致,否则会报无法定位的问题

2   查询的值必须是一个值,如果出现多行值也会报错,无法赋值的问题

案例 4  需要将表中的查询的多个值进行展示

这个问题与上面的问题类似,上面的第三个案例只能展示一行值,并且出现多行结果,会报错,而大概率的情况下,怎么处理多行值的问题就在第四个案例中展示。

1af911ac406f755193ab0795923b4073.png


create or replace procedure dba_insert_data("id_in" int,"name_in" varchar(20))
language plpgsql
as $$

declare table_record record;

BEGIN
insert into public.insert_d (id,name) values ("id_in","name_in");
     
     for table_record in (select id,name from public.insert_d)
         
         loop
             RAISE INFO 'insert data id is:%,%',table_record."id",table_record."name";
            
         end loop;

END;
$$;

案例 5  权限问题,一般在建立存储过程的时候,创建者都拥有操作这个存储过程中的OBJECT 的权限,而执行者一般不见得有所有这个存储过程中需要的OBJECT的权限,就会产生一个问题,执行者执行存储过程无法通过。所以我们就需要通过  security definer 来指定拥有存储过程的特权用户来操作这个存储过程。

下面我们通过两个不同的security 方式来进行测试

1  使用security definer 这里是采用建立这个存储过程的用户的权限来调用这个存储过程,而不会使用执行者的权限来操作这个存储过程。

4a88acef9144d8ad4fedf9d494c1f43d.png

而如果我们通过其  security invoker 的方式来定义存储过程,并且使用一个没有权限操作存储过程中OBJECT 的权限的用户来操作存储过程,则问题就会像下面的结果一样报错,并告知没有相关的权限来操作存储过程。

5f5a45e1f0bccd3c98a525701c4ce2c5.png

8a99ad014543c4dbe6951fd5f6e8c54e.png

以上仅仅是一些简单的例子和一些比较常见的存储过程的用法,其实有点好笑的是,在现在云原生和分布式数据库爆发的年代,我们还在继续使用存储过程来操作数据库,好像也没有什么错。

9c3eb512f8cbb5257ea9e01a0b356d1b.png

以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值