当前位置: 首页 > news >正文

PostgreSQL的函数、存储过程和触发器

1、PostgreSQL 运算符的优先级:

运算符                       结合性                                意思
::                                                      类型转换(与 CAST 相同)
[]                             左                           数组选择
.                             左                       对象(模式,表,列)选择
-                            右                      一元减号(负数)
^                            左                              幂
* / %                        左                         乘法运算符
+ -                          左                         加减运算符

OR                            左                          逻辑或

NOT                         右                             逻辑非
AND                          左                             逻辑与
所有其他的运算符 不在这里列出的用户定义的和内置的运算符有相同的优先级

2、PostgreSQL 的字符串运算符

运算符                              示例                          意思
||                     'abc' || 'def' 为 'abcdef'               连接字符串
~~                     'xyzzy' ~~ '%zz%'                      LIKE 的同义词
!~~                   'xyzzy' !~~ '%aa%'                     NOT LIKE 的同义词
~                      'xyzzy' ~ 'y.*y'                 正则表达式子串匹配;使用^开始或者$结 
                                                         尾来表示开始配或者结束匹配。
~*                    'xyzzy' ~* '^X.*Y$'                正则表达式匹配,不区分大小写
!~                   'xyzzy' !~ 'aa'                           不匹配(~的相反值)
!~*                   'xyzzy' !~ 'AA'                     不匹配,不区分大小写(~*的相反值)

3、常用的 PostgreSQL 字符串函数

函数                                              意思
char_length(s)
character_length(s)                          字符串长度

octet_length(s)                         存储字符串需要的长度
lower(s)                                    转换为小写
upper(s)                                    转换为大写
position(s1 in s2)                    s1 出现在 s2 中的位置
substring(s from n fro m)              从 s 的位置 n 开始获取长度为 m 的子串

trim([leading | trailing | both] [s1] from s2)     从 s2 中去除子串 s1,可以是从开始、结尾或 
                                             者同时,如果没给出 s1 则默认移除空白

4、过程语言

新建函数的 SQL 是 CREATE FUNCTION,使用以下的基本语法:

CREATE FUNCTION name ( [ ftype [, ...] ] )
 RETURNS rtype
 LANGUAGE 'langname'
 AS definition

一个非常简单的用于将一个参数增加一的函数可以这样写

CREATE FUNCTION add_one(int4) RETURNS int4 AS '
 BEGIN
 RETURN $1 + 1;
 END;
' LANGUAGE 'plpgsql';

使用 PL/pgSQL 编写存储过程的一个稍微有点复杂的问题是引号。由 CREATE FUNCTION 命令提供的整个函数的定义是一个单引号括起来的字符串。这意味着如果我们如果需要在函数定义中使用单引号,必须使用转义。我们通过使用两个连续的单引号来表示字符串中的一个单引号。如果我们的过程使用一个用嵌入了转义了的单引号的用单引号括起来的字符串,我们也必须将他们转义。这可能最终导致使用连续的四个单引号(或更多)。在 PostgreSQL 8.0 以及以后的版本中,提供了新功能美元符号引号。类似于 Perl 和 UNIX/Linux 的 shell的工作方式,美元符号引号允许我们在开始和结束的引号之间选择使用一个字符串。通过选择一个合适的不会出现在我们存储过程中的字符串,我们不需要使用转义。美元符号引用指一个在$字符之间的长度为 0 到任意长度的字符串。

在函数体内,函数的参数依照被定义的顺序被称为$1,$2,以此类推。我们将会在稍后发现可以使用 ALIAS 定义来
给参数命名。

create function geom_avg(a int4, b int4) returns float8 as $$
begin
 return sqrt(a * b::float8);
end;
$$ language plpgsql;

声明 :

PL/pgSQL 函数可以声明用于函数的局部变量。每个变量可以是一个 PostgreSQL 内置类型、用户自定义类型或者对应到一个表的行的类型。
函数的变量声明可以放在函数定义部分或者函数函数块的 DECLARE 段。和块结构语言例如 C 和 C++一样,声明的变量仅能用于对应的代码块以及包含的子块。内部块中声明名变量将隐藏对外部块中同名变量的访问:
 

DECLARE
 n1 integer;
 n2 integer;
BEGIN
 -- can use n1 and n2 in here
 n2 := 1;
 DECLARE
 n2 integer; -- hides the earlier n2
 n3 integer;
 BEGIN
 -- can use n1, n2 and n3 in here
 n2 := 2;
 END;
 -- n3 no longer available here
 -- n2 still has value 1 here
END;

别名(ALIAS):

最简单的声明访问是别名(ALIAS),用于给某个函数参数一个名字。这有助于让我们的代码更有意义,而且代码在针
对在修改参数数量或者顺序的时候显得更健壮。ALIAS 声明的语法为:
name ALIAS FOR $n;

create function geom_avg(integer, integer) returns float8 as '
declare
 first alias for $1;
 second alias for $2;
begin
 return sqrt(first * second::float8);
end;
' language 'plpgsql';

复合变量的声明:

复合变量值对应到一个特定表的完整行的变量。它有对应到表的每个列的字段。我们可以在我们的存储过程中声明和使用复合变量,可以是 rowtype 或者 record。
要声明一个符合变量,我们使用 rowtype 声明,语法如下:

name table%rowtype;
DECLARE
 contact customer%rowtype;
 address text;
BEGIN
 contact.zipcode := 'XY1 6ZZ';
 contact.fname := NULL;
 address := contact.addressline || contact.town;
...
END;

第二种复合变量声明的方法是 record 类型。这是一种和 rowtype 非常类似的类型,但它在定义的时候不是基于某个的表的。这种 record 类型将拥有运行时赋给它的任何结构。Record 在被不同表调用的触发器中非常有用,例如在一个通用的用于记录行被删除的存储过程中非常有用。它通常也可以用于存储 SELECT 语句的结果。Record 声明非常简单:

name record;

循环:

示例:

<<indefinite>>
LOOP
 n := n + 1;
 EXIT indefinite WHEN n >= 10;
END LOOP;
[<<label>>]
WHILE expression
LOOP
 statements
END LOOP;
FOR cid IN 1 .. 15
LOOP
 SELECT * INTO row FROM customer 
 WHERE customer_id = cid;
 -- process a customer
END LOOP; 

以下为在 psql 中执行的一段用于打印所有客户的姓的代码段示例:

DECLARE
 row record;
BEGIN
 FOR row IN SELECT * FROM customer
 LOOP
 RAISE NOTICE 'Family Name is %', row.lname;
 END LOOP;
...
END

SQL 函数:

CREATE FUNCTION sqlf(text) RETURNS setof customer AS $$
 SELECT * FROM customer WHERE town = $1;
$$ language sql;

5、触发器

使用命令 CREATE TRIGGER 命令建立触发器,语法如下:

CREATE TRIGGER name { BEFORE | AFTER }
 { event [OR ...] }
 ON table FOR EACH { ROW | STATEMENT }
 EXECUTE PROCEDURE func ( arguments )

在这里,event 可以是 INSERT,DELETE 或者 UPDATE。

例如:

CREATE TRIGGER trig_reorder
AFTER INSERT OR UPDATE ON stock
FOR EACH ROW EXECUTE PROCEDURE reorder_trigger(3);

注意触发器过程(本例中的 reorder_trigger)必须在建立触发器前被建立。
我们使用触发器过程参数来传递一个最小库存阈值,在本例中为 3

以下为一个触发器过程用于在 stock 表发生调整的时候更新 reorders 表的示例:

create function reorder_trigger() returns trigger AS $$
declare
 mq integer;
 item_record record;
begin
 mq := tg_argv[0];
 raise notice 'in trigger, mq is %', mq;
 if new.quantity <= mq
 then
 select * into item_record from item 
 where item_id = new.item_id;
 insert into reorders 
 values (new.item_id, item_record.description);
 end if;
 return NULL;
end;
$$ language plpgsql;

从一个脚本文件中加载这个函数和触发器的定义:

bpfinal=# \i sproc.sql
...
CREATE FUNCTION
CREATE FUNCTION1;
CREATE TRIGGER
bpfinal=#

然后尝试调整一个项目的库存让它降低到 3 或者更少:

bpfinal=# UPDATE stock SET quantity = 3 WHERE item_id = 1;
NOTICE: in trigger, mq is 3
UPDATE 1
bpfinal=#

解析:首先,触发器过程的参数不在是$1,$2 一类的了。自动触发的过程是通过一大批特殊变量之一实现参数传递的。这个以数组方式传递的参数名为 TG_ARGV,从 TG_ARGV[0]开始。触发器过程使用的特殊变量在下表中列出:

 PostgreSQL 触发器过程变量:

变量                        描述
NEW                     包含新数据库行的记录
OLD                       包含旧数据库行的记录
TG_NAME                   包含触发这个触发器过程的运行的触发器名字的变量
TG_WHEN                       包含文本’BEFORE’或者’AFTER’的变量,依赖于触发器类型
TG_LEVEL               包含文本’ROW’或者’STATEMENT’的变量,依赖于触发器的定义
TG_OP              包含文本’INSERT’,’DELETE’或者’UPDATE’的变量,依赖于导致触发器被触发的事件
TG_RELID                    触发器被激活的表所关联的对象 ID
TG_RELNAME               触发器被触发的表的名字
TG_NARGS                 整数型变量,包含在触发器定义的时候传入的参数个数
TG_ARGV               字符串数组,包含过程调用的参数,索引值从 0 开始;如果传入无效的索引值则返回 NULL

 

相关文章:

  • PostgreSQL实战(1)允许远程连接
  • Phoenix官方教程 (五) 控制器
  • PostgreSQL实战(12)高级特性
  • base64图上上传保存到服务器
  • ajax报错302重定向错误
  • ArcGIS Engine开发之旅03--ArcGIS Engine中的控件
  • kafka消费过程中失败,kafka重试补偿
  • 从0到1搭建属于自己的服务器
  • PostgreSQL实战(2)数据结构
  • 金蝶kis记账王初始化过程中如何设置科目
  • SpringBoot项目的jar包在启动时选择的多环境配置以及加载顺序
  • PostgreSQL中date数据类型
  • springmvc带参数链接跳转,实现单一样式容器
  • Spring Boot 打包分为 war 格式,放到Tomcat下报错的解决方案
  • 窗体的事件
  • 时间复杂度分析经典问题——最大子序列和
  • [译]CSS 居中(Center)方法大合集
  • Bootstrap JS插件Alert源码分析
  • Computed property XXX was assigned to but it has no setter
  • GitUp, 你不可错过的秀外慧中的git工具
  • Hibernate【inverse和cascade属性】知识要点
  • JavaScript创建对象的四种方式
  • maya建模与骨骼动画快速实现人工鱼
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • socket.io+express实现聊天室的思考(三)
  • Vue 重置组件到初始状态
  • Yii源码解读-服务定位器(Service Locator)
  • 成为一名优秀的Developer的书单
  • 大快搜索数据爬虫技术实例安装教学篇
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 优化 Vue 项目编译文件大小
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 阿里云ACE认证之理解CDN技术
  • 阿里云移动端播放器高级功能介绍
  • ​Spring Boot 分片上传文件
  • ​比特币大跌的 2 个原因
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #{}和${}的区别?
  • #WEB前端(HTML属性)
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (超详细)语音信号处理之特征提取
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • ***测试-HTTP方法
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET Framework 4.6.2改进了WPF和安全性
  • .Net Memory Profiler的使用举例
  • .NET 指南:抽象化实现的基类
  • ??在JSP中,java和JavaScript如何交互?
  • [ C++ ] STL_stack(栈)queue(队列)使用及其重要接口模拟实现
  • [ C++ ] STL---string类的模拟实现
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧
  • [<死锁专题>]