postgresql-触发器

postgresql-触发器

  • 触发器概述
  • 创建触发器
  • 管理触发器
  • 删除触发器
  • 事件触发器
    • 创建事件触发器
    • 修改触发器
    • 删除事件触发器

触发器概述

PostgreSQL 触发器(trigger)是一种特殊的函数,当某个数据变更事件(INSERT、UPDATE、
DELETE 或者 TRUNCATE 语句)或者数据库事件(DDL 语句)发生时自动执行,而不是由用
户或者应用程序进行调用

基于某个表或者视图数据变更的触发器被称为数据变更触发器(DML 触发器),基于数据
库事件的触发器被称为事件触发器(DDL 触发器)。一般我们更多使用的是数据变更触发器
在这里插入图片描述
对于数据变更触发器,PostgreSQL 支持两种级别的触发方式:行级(row-level)触发器和 语句级(statement-level)触发器。这两者的区别在于触发的时机和触发次数。例如,对于一个
影响 20 行数据的 UPDATE 语句,行级触发器将会触发器 20 次,而语句级触发器只会触发 1 次

触发器可以在事件发生之前(BEFORE)或者之后(AFTER)触发。如果在事件之前触发,
它可以跳过针对当前行的修改,甚至修改被更新或插入的数据;如果在事件之后触发,触发器可
以获得所有的变更结果。INSTEAD OF 触发器可以用于替换数据变更的操作,但只能基于视图
定义

下表列出了 PostgreSQL 中支持的各种触发器:

触发时机触发事件行级触发器语句级触发器
beforeinsert update delete表和外部表表、视图和外部表
beforetruncate
afterinsert update delete表和外部表表 视图和外部表
aftertruncate
instead ofinsert update delete视图

触发器对于多应用共享的数据库而言非常有用,可以将跨应用的功能存储在数据库中,当表
中的数据发生任何变化时都会自动执行触发器的操作。例如,可以用触发器实现数据修改的历史
审计,而不需要各种应用程序实现任何相关的逻辑。

另外,触发器还可以用于实现复杂的数据完整性和业务规则。例如,在非业务时间不允许修
改用户的信息。

但是另一方面,触发器可能带来的问题就是在不清楚它们的存在和逻辑时可能会影响数据修
改的结果和性能。

创建触发器

PostgreSQL 触发器的创建分为两步:

  1. 使用 CREATE FUNCTION 语句创建一个触发器函数
  2. 使用 CREATE TRIGGER 语句将该函数与表进行关联
-- 语法
CREATE [ OR REPLACE ] FUNCTION trigger_function ()RETURNS trigger
AS $$
DECLAREdeclarations
BEGINstatements;...
END; $$
LANGUAGE plpgsql;

触发器函数与普通函数的区别在于它没有参数,并且返回类型为 trigger;在触发器函数的内部,系统自动创建了许多特殊的变量:

  • NEW ,类型为 RECORD,代表了行级触发器 INSERT、UPDATE 操作之后的新数据行。
    对于 DELETE 操作或者语句级触发器而言,该变量为 null;
  • OLD,类型为 RECORD,代表了行级触发器 UPDATE、DELETE 操作之前的旧数据行。
    对于 INSERT 操作或者语句级触发器而言,该变量为 null;
  • TG_NAME,触发器的名称;
  • TG_WHEN,触发的时机,例如 BEFORE、AFTER 或者 INSTEAD OF
  • TG_LEVEL,触发器的级别,ROW 或者 STATEMENT;
  • TG_OP,触发的操作,INSERT、UPDATE、DELETE 或者 TRUNCATE;
  • TG_RELID,触发器所在表的 oid;
  • TG_TABLE_NAME,触发器所在表的名称;
  • TG_TABLE_SCHEMA,触发器所在表的模式;
  • TG_NARGS,创建触发器时传递给触发器函数的参数个数;
  • TG_ARGV[],创建触发器时传递给触发器函数的具体参数,下标从 0 开始。非法的下标
    (小于 0 或者大于等于 tg_nargs)将会返回空值。
-- 使用 CREATE TRIGGER 语句创建一个触发器,语法如下:
CREATE TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF} {event [OR ...]}ON table_name[FOR [EACH] {ROW | STATEMENT}][WHEN ( condition ) ]EXECUTE FUNCTION trigger_function;

其中,event 可以是 INSERT、UPDATE、DELETE 或者 TRUNCATE,UPDATE 支持特定字
段(UPDATE OF col1, clo2)的更新操作;触发器可以在事件之前(BEFORE)或者之后(AFTER)
触发,INSTEAD OF 只能用于替代视图上的 INSERT、UPDATE 或者 DELETE 操作;FOR EACH
ROW 表示行级触发器,FOR EACH STATEMENT 表示语句级触发器;WHEN 用于指定一个额
外的触发条件,满足条件才会真正支持触发器函数

我们通过触发器来实现记录员工的信息变更历史,首先创建一个历史记录表
employees_history:

create table employees_history (id serial primary key,employee_id int null,first_name varchar(20) null,last_name varchar(25) null,email varchar(25) null,phone_number varchar(20) null,hire_date date null,job_id varchar(10) null,salary numeric(8,2) null,commission_pct numeric(2,2) null,manager_id int null,department_id int null,action_type varchar(10) not null,change_dt timestamp not null
);
-- 定义一个触发器函数 track_employees_change
-- 该函数根据不同的操作记录了相应的历史信息、操作类型和操作时间。
create or replace function track_emp_change()
returns trigger 
as $$
begin -- tg_op 触发的操作 if tg_op = 'INSERT' theninsert into public.employees_history(employee_id, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id,department_id, action_type, change_dt)values(new.employee_id, new.first_name, new.last_name, new.email, new.phone_number, new.hire_date, new.job_id, new.salary,new.commission_pct, new.manager_id, new.department_id,'INSERT',current_timestamp);elsif tg_op = 'UPDATE' theninsert into public.employees_history(employee_id, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id,department_id, action_type, change_dt)values(old.employee_id, old.first_name, old.last_name, old.email, old.phone_number, old.hire_date, old.job_id, old.salary,old.commission_pct, old.manager_id, old.department_id,'UPDATE',current_timestamp);elsif tg_op = 'DELETE' theninsert into public.employees_history(employee_id, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id,department_id, action_type, change_dt)values(old.employee_id, old.first_name, old.last_name, old.email, old.phone_number, old.hire_date, old.job_id, old.salary,old.commission_pct, old.manager_id, old.department_id, 'DELETE',current_timestamp);end if;return new;
end $$
language plpgsql;
-- 最后创建一个触发器 trg_employees_change,将该函数与 employees 进行关联:
create trigger trg_employees_changebefore insert or UPDATE or DELETEon employeesfor each rowexecute function public.track_emp_change();
-- 测试
insert into employees(employee_id, first_name, last_name, email, phone_number,
hire_date, job_id, salary, commission_pct, manager_id, department_id)
values(208, 'Tony', 'Dong', 'TonyDong', '01066665678', '2020-05-25',
'IT_PROG', 6000, null, 103, 60);
SELECT * FROM employees_history;
--我们往 employees 中插入一条记录之后,employees_history 记录了这一操作历史;对于
--UPDATE 和 DELETE 操作也是如此

在这里插入图片描述

管理触发器

PostgreSQL 提供了 ALTER TRIGGER 语句,用于修改触发器:

-- 修改触发器的名称
ALTER TRIGGER name ON table_name RENAME TO new_name;
-- PostgreSQL 还支持触发器的禁用和启用:
ALTER TABLE table_name
{ENABLE | DISABLE} TRIGGER {trigger_name | ALL | USER};

默认创建的触发器处于启用状态;我们也可以使用以上语句禁用或者启用某个触发器、某个
表上的所有触发器(ALL)或用户触发器(不包括内部生成的约束触发器,例如用于外键约束或
延迟唯一性约束以及排除约束的触发器)

视图 information_schema.triggers 中存储了关于触发器的信息

select * from information_schema.triggers;

在这里插入图片描述

删除触发器

-- 被禁用的触发器仍然存在,只是不会被触发;如果想要删除触发器,可以使用 DROP TRIGGER 语句
DROP TRIGGER [IF EXISTS] trigger_name
ON table_name [RESTRICT | CASCADE];

IF EXISTS 可以避免触发器不存在时的错误提示;CASCADE 表示级联删除依赖于该触发器
的对象,RESTRICT 表示如果存在依赖于该触发器的对象返回错误,默认为 RESTRICT

-- 将 employees 表上的触发器 trg_employees_change 删除
-- 虽然删除了触发器,但是触发器函数 track_employees_change 仍然存在。
drop trigger trg_employees_change on employees;

在这里插入图片描述

事件触发器

除了数据变更触发器之外,PostgreSQL 还提供了另一种触发器:事件触发器 。事件触发器
主要用于捕获全局的 DDL 事件,目前支持 ddl_command_start、ddl_command_end、table_rewrite
和 sql_drop,这些事件支持的完整语句可以参考官网

对于事件触发器的函数而言,同样预定义了两个变量:

  • TG_EVENT,触发事件;
  • TG_TAG,触发语句。
    对于事件触发器,首先也需要创建一个函数,返回类型为 event_trigger
create or replace function abort_any_command()
returns event_trigger
as $$
begin 
-- 判断当前操作用户是否为超级用户(postgres),如果不是则不允许执行任何 DDL语句。if (user != 'postgres') thenraise exception '禁止%命令',tg_tag;	end if;
end $$
language plpgsql;

创建事件触发器

-- 使用 create event trigger 语句创建事件触发器:
create event trigger abort_ddl on ddl_command_startexecute function abort_any_command();

修改触发器

-- alter event trigger 语句可以启用/禁用事件触发器或者修改触发器的名称等:
alter event trigger name disable;
alter event trigger name enable;
alter event trigger name rename to new_name;

删除事件触发器

--drop event trigger 语句可以用于删除事件触发器:
drop event trigger [ if exists ] name [ cascade | restrict ];
-- 删除事件触发器 abort_ddl 
drop event trigger abort_ddl;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/86380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【3dmax】怎么将点删除而面保留

在编辑多边形模式下,选择点模式,选择要删除的点,在下拉面板中找到【移除】

Mysql——压缩包方式安装教程

一.Mysql压缩包下载方式 zip版(5.7及8.0)的下载需到官方网站下载,不同版本对应能安装在不同的操作系统下,本次介绍的是mysql-8.0.30-winx64在win10下的安装方式。 下载网址:MySQL :: Download MySQL Community Server …

描述符——配置描述符

描述符定义 描述符实现 /*** brief USB configuration descriptor.*/ typedef struct __attribute__ ((packed)) {uint8_t bLength ; /**< Size of this descriptor in bytes. */uint8_t bDescriptorType ; /**< CONFIGURATION Descriptor Type. */ui…

基于同名面片的TLS测站点云配准

1、原理介绍 2、代码介绍 基于C++编写的程序代码如下,其依赖eigen矩阵运算库,在创建工程时包含库目录中使用了相对路径,因此其下载下来直接可以运行,不用单独在设置环境,非常方便。

云原生微服务治理:服务发现、负载均衡与熔断策略

文章目录 什么是云原生微服务治理&#xff1f;服务发现客户端发现服务器端发现 负载均衡Ribbon - 基于客户端的负载均衡Nginx - 基于服务器的负载均衡 熔断策略Hystrix - 熔断器模式 结论 &#x1f389;欢迎来到云计算技术应用专栏~云原生微服务治理&#xff1a;服务发现、负载…

Spring Cloud Gateway快速入门(二)——断言工厂

文章目录 前言1. 什么是Gateway断言工厂2. 为什么要使用断言2.1. 调试和开发&#xff1a;2.2. 防御性编程&#xff1a;2.3. 文档和可读性&#xff1a;2.4. 测试&#xff1a; 3. 常用的Gateway断言工厂3.1 Path断言工厂3.2 Method断言工厂3.3 Header断言工厂3.4 时间断言工厂 4.…

北邮22级信通院数电:Verilog-FPGA(1)实验一“跑通第一个例程” 过程中遇到的常见问题与解决方案汇总(持续更新中)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 问题一&#xff1a;Verilog代码没有跑通 报…

LabVIEW使用ModbusTCP协议构建分布式测量系统

LabVIEW使用ModbusTCP协议构建分布式测量系统 分布式测量系统主要用于监控远程物体。这种系统允许对系统用户获得的数据进行全面的数据收集、处理、存储和组织访问。它们可能包括许多不同类型的传感器。 在任何具有互联网接入的个人计算机上运行的软件都会发送来自传感器的测…

SpringCloud Alibaba - Sentinel

接上文SpringCloud Alibaba - Nacos 1.Sentinel 流量防卫兵 1.1 安装与部署 和Nacos一样&#xff0c;它是独立安装和部署的&#xff0c;下载地址https://github.com/alibaba/Sentinel/releases 下载后的jar放到目录 然后配置 启动并访问,用户名密码都是 sentinel 此时就…

Springboot整合分页插件pagehelper

首先需要有一定的springbootmybatis的基础&#xff0c;才能使用顺畅 项目结构如下 引入依赖&#xff0c;springboot版本选的是2.7.16版本&#xff0c;jdk选的17&#xff0c; <!--分页插件--> <dependency><groupId>com.github.pagehelper</groupId><…

滑动窗口9.23

1876.长度为3且各字符不同的子字符串 1876. 长度为三且各字符不同的子字符串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/substrings-of-size-three-with-distinct-characters/?envTypelist&envId24zW97w8自写思路&#xff1a; 数组充当哈希表…

useCallBack

React.memo 保证了只有props发生变化时&#xff0c;该组件才会重新渲染 &#xff08;当然组件内部的state 和 context 变化也会导致组件重新渲染&#xff09;&#xff0c;但咱们只要将咱们的子组件包裹&#xff0c;便可以保证Child组件在props不变的情况下&#xff0c;不会重新…

【C语言】指针经典笔试题(上)

C语言的一大重头戏就是指针。 对于指针有一些认识&#xff1a; 1.指针是存放变量的地址&#xff0c;一般说的指针和指针变量是一个概念。 2.地址的单位是字节&#xff0c;大小在不同编译器环境下有所不同&#xff0c;32位机器是4个字节&#xff0c;64位机器是8个字节。 3.数组名…

学会使用Git 和 GitHub

Git 和 GitHub 都是程序员每天都要用到的东西 —— 前者是目前最先进的 版本控制工具&#xff0c;拥有最多的用户&#xff0c;且管理着地球上最庞大的代码仓库&#xff1b;而后者是全球最大 同性交友 代码托管平台、开源社区。 在没有这两个工具时&#xff0c;编程可能是这样的…

Floyd算法基础

弗洛伊德算法(Floyd) 之前介绍了迪杰斯特拉算法(Dijkstra)。具体请看&#xff1a;最短路径算法——简单明了的迪杰斯特拉算法(Dijkstra)。Dijkstra适用于非负权图&#xff0c;并且一次只能从网络中找源点到任何一个节点的最短路径&#xff0c;而Floyd算法的应用更加广泛&#…

【C刷题】day3

一、选择题 1、已知函数的原型是&#xff1a; int fun(char b[10], int *a); &#xff0c;设定义&#xff1a; char c[10];int d; &#xff0c;正确的调用语句是&#xff08; &#xff09; A: fun(c,&d); B: fun(c,d); C: fun(&c,&d); D: fun(&c,d); 【答案…

正则表达式新解

文章目录 是什么&#xff1f;正则用法匹配单个字符匹配一组字符其他元字符核心函数 贪婪匹配和非贪婪匹配正则练习 是什么&#xff1f; 正则表达式(Regular Expression)是一种文本模式&#xff0c;包括普通字符&#xff08;例如&#xff0c;a 到 z 之间的字母&#xff09;和特殊…

算法leetcode|83. 删除排序链表中的重复元素(rust重拳出击)

文章目录 83. 删除排序链表中的重复元素&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 83. 删除排序链表中的重复元素&#xff1a; 给…

ChatGLM GPT原理介绍

图解GPT 除了BERT以外,另一个预训练模型GPT也给NLP领域带来了不少轰动,本节也对GPT做一个详细的讲解。 OpenAI提出的GPT-2模型(https://openai.com/blog/better-language-models/) 能够写出连贯并且高质量的文章,比之前语言模型效果好很多。GPT-2是基于Transformer搭建的,相…

注解,自定义注解

一、什么是注解 二、自定义注解 /*** 自定义注解*/public interface MyAnnotation {String aaa();boolean bbb() default true;String ccc(); }MyAnnotation ( aaa "牛魔王",ccc "sss") public class Test {MyAnnotation ( aaa "aaa",ccc &q…