一、概述

1、什么是触发器

触发器的功能就是为了解决这类问题而设计的,当你更新或查询某个资料表时会触动触发器,触发器就会照您所设计的流程,同步去插入、更新、删除其他资料,你不再需要重复下达多次的SQL命令就能达成一连串资料的同步处理。

触发器是某个数据库操作发生时被自动调用的函数。可以在INSERTUPDATEDELETE操作之前或之后调用触发器。PostgreSQL支持两种类型的触发器,一种是数据行级触发器,另外一种是语句级触发器。对于数据行级的触发器,触发发触发器的语句每操作一个数据行,它就被执行一次。对于语句级的触发器,它只会被执行一次。

创建触发器以前,必须定义触发器使用的函数。这个函数不能有任何参数,它的返回值的类型必须是trigger函数定义好以后,用命令CREATE TRIGGER创建触发器。多个触发器可以使用同一个函数。

2、语句级触发器与行级触发器

  • 语句级的触发器是指执行每个 SQL 时,只执行一次,行级触发器则指每行都会执行一次。

  • 一个修改零行的操作会导致合适的语句级触发器被执行,但不会触发行级触发器。

  • 批量插入时,语句级别的触发器只触发一次,不管 affected row 是否为 0,但是行级触发器的触发次数为 affected row。

3、触发器的调用时机

触发器按按执行的时间被分为 before触发器after触发器

  • 语句级的 before触发器 在语句开始执行前被调用,
  • 语句级的 after触发器 在语句开始执行结束后被调用。
  • 数据行级的 before触发器 在操作每个数据行以前被调用,
  • 数据行级的 after触发器 在操作每个数据行以后被调用。

4、触发器的返回值

**语句级的触发器应该总是返回NULL。**即必须显式地在触发器函数中写上 RETURN NULL,如果没有写,将导致出错。报错信息如下所示:

行级的 before触发器 的返回值不同,它对触发操作的影响也不同。

  • 如果它返回NULL,触发这个触发器的INSERT UPDATE DELETE命令不会被执行。
  • 如果返回非空的值,则INSERT UPDATE DELETE 命令继续执行。
  • 对于UPDATEINSERT操作触发的行级before触发器,如果它返回的数据行与更新以后的或被插入的数据行不相同,则以触发器返回的数据行作为新的更新以后的数据行和被插入的数据行。

行级after触发器的返回值总是被忽略,可以返回NULL。

  • 如果同一表上,对同一个事件定义了多个触发器,这些触发器将按它们的名字的字母顺序被触发。
  • 对于行级before触发器来说,前一个触发器返回的数据行作为后一个触发器的输入。如果任何一个行级before触发器返回NULL,后面的触发器将停止执行,触发触发器的INSERT UPDATE DELETE命令也不会被执行。

5、注意项

行级 before 触发器一般用于 检查修改 将被插入和更新的数据。 行级 after 触发器一般用于将表中被更新的数据记录到其它的表中,或者检查与其它的表中的数据是否是一致的。

before触发器的执行效率比after触发器高,在before触发器和after触发器都能被使用的情况下,应该选择before触发器。

一个触发器在执行的过程中,如果执行了其它的 SQL 命令,可能会触发其它的触发器,这被称作触发器级联。对于触发器级联的层次,系统没有任何限制,但触发器级联可能会调用前面已经执行过的触发器,从而引起死循环,系统不会检测这种现象,定义触发器的用户应该保证这种现象不会发生。

定义触发器的时候,也可以为它指定参数(在CREATE TRIGGER命令中中指定)。系统提供了特殊的接口来访问这些参数。

触发器在被调用时,系统会自动传递一些数据给它,这些数据包括触发触发器的事件类型(例如INSERTUPDATE),对于行级触发器,还包括 NEW 数据行(对于INSERTUPDATE触发器)和OLD数据行(对于UPDATEDELETE触发器)。每种可以用来书写触发器函数的语言都提供了取这些数据的方法。

语句级别的触发器在执行过程中,无法查看该语句插入、删除或更新的任何数据行。

还有一种特殊的触发器叫约束触发器,这种触发器的执行时间可以被命令 SET CONSTRAINTS 控制,详细信息参考《SQL命令手册》对CREATE CONSTRAINT TRIGGER 命令的解释。

6、数据可见规则

触发器在执行过程中,如果执行 SQL 命令访问触发器的父表中的数据,这些SQL命令遵循下面的数据可见规则,这些规则决定它们能否看见触发触发器的操作修改的表中的数据行:

1)语句级的before触发器在执行过程中,该语句的所有的对表中的数据的更新对它都不可见。语句级的after触发器在执行过程中,该语句的所有的对表中的数据的更新对它都可见。

2)行级before触发器在执行过程中,前面所有的已经被同一个命令处理的数据行对它是可见的,但触发该触发器的数据行的更新操作的结果(插入、更新或删除)对它是不可见的。行级after触发器在执行过程中,前面所有的已经被同一个命令处理的数据行对它是可见的。

7、触发器函数中的特殊变量

当把一个 PL/pgSQL 函数当作触发器函数调用的时候,系统会在顶层的声明段里自动创建几个特殊变量,比如在之前例子中的 “NEW”、“OLD”、“TG_OP” 变量等。可以使用的变量有如下这些。

  1. NEW:该变量为 INSERT/UPDATE 操作触发的行级触发器中存储的新的数据行,数据类型是 RECORD。在语句级别的触发器里此变量没有分配,DELETE 操作触发的行级触发器中此变量也没有分配。
  2. OLD:该变量为 UPDATE/DELETE 操作触发的行级触发器中存储的旧数据行,数据类型是 RECORD。在语句级别的触发器里此变量没有分配, INSERT 操作触发的行级触发器中此变量也没有分配。
  3. TG_NAME:数据类型是 name,该变量包含实际触发的触发器名。
  4. TG_WHEN: 内容为 BEFORE 或 AFTER 的字符串,用于指定是 BEFORE 触发器还是 AFTER 触发器。
  5. TG_LEVEL: 内容为 ROW 或 STATEMENT 的字符串用于指定是语句级触发器还是行级触发器。
  6. TG_OP: 内容为 INSERT、UPDATE、DELETE、TRUNCATE 之一的字符串,用于指定 DML 语句的类型。
  7. TG_RELID: 触发器所在表的 OID
  8. TG_RELNAME: 数据类型是 name,表示触发器作用的表的名字。它与下面的变量TG_TABLE_NAME的作用是一样的。
  9. TG_TABLE_NAME: 触发器所在表的名称。
  10. TG_TABLE_SCHEMA: 触发器所在表的模式。
  11. TG_NARGS: 在 CREATE TRIGGER 语句里面赋予触发器过程的参数个数。
  12. TG_ARGV[]: 为 text 类型的一个数组;是 CREATE TRIGGER 语句里的参数。

二、触发器的操作

1、查看触发器

select * from information_schema.triggers

2、创建触发器

(1)创建触发器的语法如下:

CREATE [ CONSTRAINT ] TRIGGER name
{ BEFORE | AFTER | INSTEAD OF } { event [ OR ... ]}
ON table_name
[ FROM referenced_table_name ]
{ NOT DEFERRABLE | [ DEFEREABLE ] { IINITIALLY IMMEDIATE | INITIALLY DEFERED} }
FOR [ EACH ] { ROW | STATEMENT }
[ WHEN { condition }]
EXECUTE PROCEDURE function_name ( arguments )CREATE [OR REPLACE] TRIGGER TRIGGER_NAME
{BEFORE | AFTER} TRIGGER_EVENT
ON TABLE_NAME
[FOR EACH ROW]
[WHEN TRIGGER_CONDITION]
TRIGGER_BODY语法解释:
TRIGGER_NAME  触发器名称
BEFORE | AFTER  指定触发器是在触发事件发生之前触发或者发生之后触发
TRIGGER_EVENT 触发事件,在DML触发器中主要为INSERT、UPDATE、DELETE等
TABLE_NAME  表名,表示发生触发器作用的对象
FOR EACH ROW  指定创建的是行级触发器,若没有该子句则创建的是语句级触发器
WHEN TRIGGER_CONDITION  添加的触发条件
TRIGGER_BODY  触发体,是标准的PL/SQL语句块

(2)创建触发器的步骤:

先为触发器建一个执行函数,此函数的返回类型为触发器类型 trigger;然后即可创建相应的触发器。

例如当删除学生表(student)中的一条记录时,把这个学生在成绩表 (score) 中的成绩记录也删除掉,这时就可以使用触发器。

(3)先建触发器的执行函数:

CREATE OR REPLEASE FUNCTION student_delete_trigger_fun()
returns trigger as $$
begindelete from score where student_no = old.student_no;return old;
end;
$$
language plpgsql;

(4)再创建这个触发器:

CREATE TRIGGER delete_student_trigger
after delete on student
for each row execute procedure student_delete_trigger_fun();

3、删除触发器

语法如下:

# DROP TRIGGER IF EXISTS 触发器名称 ON 表名称;
DROP TRIGGER [ IF EXISTS ] NAME ON TABLE [ CASCADE | RESTRICT ];

删除触发器时,触发器的函数不会被删除。不过,当表删除时,表上的触发器也会被删除,你可以使用 DROP FUNCTION fun_name 直接删除触发器函数。

四、案例

1、简单案例

将添加到student表中的数据,同步添加到user表。

-- 触发器函数
CREATE OR REPLACE FUNCTION "public"."student_trigger_fun"() RETURNS trigger  AS $BODY$BEGINIF  (TG_OP='INSERT') THEN INSERT INTO user values(NEW.id,NEW.name,NEW.age);END IF;RETURN NEW;END;$BODY$LANGUAGE 'plpgsql';-- 触发器
CREATE TRIGGER student_trigger AFTER INSERT OR UPDATE ON "public"."student"
FOR EACH ROW
EXECUTE PROCEDURE "public"."student_trigger_fun"();

2、进阶案例

将对student表的增、删、改操作,同步更新到user表。

-- 触发器函数
CREATE OR REPLACE FUNCTION "public"."student_trigger_fun"()
RETURNS TRIGGER AS $BODY$ BEGINIF( TG_OP = 'INSERT') THENINSERT INTO USER VALUES (NEW.id, NEW.name, NEW.age);RETURN NEW;ELSIF( TG_OP = 'UPDATE') THENUPDATE USER SET id=NEW.id, name=NEW.name, age=NEW.age WHERE id=OLD.id;RETURN NEW;ELSIF( TG_OP = 'DELETE') THENDELETE USER WHERE id=OLD.id;RETURN OLD;END IF;
END;
$BODY$ LANGUAGE'plpgsql';-- 触发器
CREATE TRIGGER student_trigger AFTER INSERT OR UPDATE ON "public"."student"
FOR EACH ROW
EXECUTE PROCEDURE "public"."student_trigger_fun"();

五、事件触发器

创建事件触发器的语法如下:

CREATE EVENT TRIGGER
ON event
[ WHEN filter_variable IN (filter_value [,...]) [ and ...]]
EXECUTE PROCEDURE function_name()

在创建事件触发器之前,必须先创建触发器函数,事件触发器函数的返回类型为 event_trigger,注意,其与普通触发器函数的返回类型 (trigger)是不一样的。

在官方手册中,有一个禁止所有 DDL 语句的例子,如下:

CREATE OR REPLACE FUNCTION abort_any_command()
returns event_trigger
language plpgsql
AS $$
BEGINRAISE EXCEPTION 'command % is disabled', tg_tag;
END;
$$;CREATE EVENT TRIGGER abort_DDL ON DDL_command_start
EXECUTE PROCEDURE abort_any_command();

现在执行 DDL 语句将会报错

如果想再允许 DDL 操作,可以禁止事件触发器,

ALTER EVENT TRIGGER abort_ddl DISABLE;

TG_EVENT: 为 “ddl_command_start”、“ddl_command_end”、“sql_drop” 之一。

TG_TAG: 只具体的哪种 DDL 操作,如 “CREATE TABLE”、“DROP TABLE” 等。

六、参考

https://www.yiibai.com/postgresql/postgresql-trigger.html

postgreSQL触发器相关推荐

  1. PostgreSQL触发器的使用

    原文: https://www.yiibai.com/postgresql/postgresql-trigger.html -------------------------------------- ...

  2. 获取postgreSQL触发器作用的表名

    select pg_class.relname from pg_class inner join pg_trigger on pg_trigger.tgrelid = pg_class.oid whe ...

  3. 【Postgresql】触发器某个字段更新时执行,行插入或更新执行

    [Postgresql]触发器某个字段更新时执行,行插入或更新执行 1. postgresql触发器 2. 触发器的创建及示例 1) 字段更新时,触发 2) 行插入或更新时,触发 3. 触发器的删除 ...

  4. postgresql开发中可能有用的知识

    2019独角兽企业重金招聘Python工程师标准>>> postgresql手册 一.PostgreSQL中可以直接对时间进行加减运算: 查询系统当前时间: select now() ...

  5. PostgreSQL — 常规操作

    目录 文章目录 目录 用户管理 库操作 表操作 INSERT 语句 SELECT 语句 WHERE 语句 LIKE 语句 AND & OR 语句 ORDER BY 语句 JOIN 语句 VIE ...

  6. SQL格式日志转为syslog格式:触发器中执行Shell命令

    很多企业网中都部署了日志中心,集中收集.分析和处理各种设备产生的日志. 但一些应用系统的日志是保存在数据库表中,如果需要提供syslog格式日志,除了进行代码改造外,一种快速的解决方法是使用SQL触发 ...

  7. PostgreSQL 179个场景

    案例 1.<多字段,任意组合(0建模) - 毫秒级实时圈人 - 最佳实践> 2.<IoT(物联网)极限写入.消费 最佳实践 - 块级(ctid)扫描> 3.数据采样和脱敏实践 ...

  8. PostgreSQL 数据库安全指南

    PostgreSQL 数据库安全指南 TAG 27 , TAG 6 作者 digoal 日期 2015-06-01 标签 PostgreSQL , 数据库安全指南 背景 数据库在一个企业中通常都处于非 ...

  9. Postgresql学习笔记-高级语法篇

    Postgresql学习笔记-高级语法篇 Postgresql 约束 Postgresql约束用于规定表中的数据规则. 如果存在违反约束的数据行为,行为会被约束终止. 约束可以在创建表的时候就规定(通 ...

最新文章

  1. Python 正则表达式
  2. Hybird混合开发APP初学体验
  3. 两个byte[]拼接
  4. 人脸检测中,如何构建输入图像金字塔
  5. 如何在string.Format方法中输出大括号({})
  6. Libreoffice实现office转pdf、html、jpg等格式数据
  7. 单片机ADC采样算法----加权递推平均滤波法
  8. 用aspnetpager实现datalist分页
  9. C#记事本的简单开发
  10. C#操作XML的完整例子——XmlDocument篇(转载,仅做学习之用)
  11. 高速信号传输约翰逊 pdf_?高速滑环生产加工问题的具体分析
  12. iconfont-阿里巴巴矢量图标库的使用方法
  13. Go语言躲坑经验总结
  14. GGGIS地图下载器
  15. 微信小程序防止快速点击(节流)
  16. Java 处理英文文本标点符号去除
  17. CPU、MPU、MCU和SOC还傻傻分不清楚 看这篇文章就够了
  18. 第三方支付宝API应用流程
  19. Python格式化新年祝福语
  20. linux查看sriov端口,sriov查看pf-vf对应关系

热门文章

  1. C语言程序——分段函数
  2. 世界十大免费电子书网站地址
  3. 【数据结构】稀疏矩阵的介绍
  4. 云谷计算机华南,广州南沙云谷机房,广州南沙云谷数据中心
  5. 解决Configuration is faulty. Check the Issues view for details. Error while building/deploying project
  6. python为源文件指定系统默认字符编码是_系统编码、文件编码与python系统编码
  7. java各种符号用法_Java正则的基本用法一:符号
  8. UIApplicationOpenSettingsURLString闪退
  9. 关于客户背景调查的两个案例,说下我的真实看法
  10. linux查看日志保留时间多长的命令,Linux系统日志的一些讲解