当前位置: 代码迷 >> 综合 >> PostgreSQL的函数、存储过程和触发器
  详细解决方案

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

热度:87   发布时间:2023-09-19 14:48:52.0

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 rtypeLANGUAGE 'langname'AS definition

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

CREATE FUNCTION add_one(int4) RETURNS int4 AS 'BEGINRETURN $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 $$
beginreturn sqrt(a * b::float8);
end;
$$ language plpgsql;

声明 :

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

DECLAREn1 integer;n2 integer;
BEGIN-- can use n1 and n2 in heren2 := 1;DECLAREn2 integer; -- hides the earlier n2n3 integer;BEGIN-- can use n1, n2 and n3 in heren2 := 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 '
declarefirst alias for $1;second alias for $2;
beginreturn sqrt(first * second::float8);
end;
' language 'plpgsql';

复合变量的声明:

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

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

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

name record;

循环:

示例:

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

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

DECLARErow record;
BEGINFOR row IN SELECT * FROM customerLOOPRAISE 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 $$
declaremq integer;item_record record;
beginmq := tg_argv[0];raise notice 'in trigger, mq is %', mq;if new.quantity <= mqthenselect * 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

 

  相关解决方案