Learning PostgresSQL读书笔记: 第8章 Triggers and Rules

本章将讨论以下内容:
• 探索 PostgreSQL 中的规则
• 管理 PostgreSQL 中的触发器
• 事件触发器

探索 PostgreSQL 中的规则

文档中的这段话阐述了rule和trigger的区别:

PostgreSQL 规则系统允许定义在数据库表中插入、更新或删除时执行的替代操作。粗略地说,当对给定表执行给定命令时,规则会执行其他命令。或者,INSTEAD 规则可以用另一个命令替换给定命令,或者导致命令根本不执行。规则也用于实现 SQL 视图。重要的是要认识到规则实际上是一种命令转换机制或命令宏。转换发生在命令开始执行之前。如果您确实想要一个针对每个物理行独立触发的操作,则可能需要使用触发器而不是规则。

简单来说,rule和trigger接收到触发事件的操作时,可以:

  • 替换为新的操作(INSTEAD)
  • 额外做新的操作(ALSO)
  • 什么都不做(INSTEAD NOTHING)

理解 OLD 和 NEW 变量

这两个称为pseudorelations。说明见这里。

  • NEW 记录
    行级触发器中 INSERT/UPDATE 操作的新数据库行。此变量在语句级触发器和 DELETE 操作中为空。
  • OLD 记录
    行级触发器中 UPDATE/DELETE 操作的旧数据库行。此变量在语句级触发器和 INSERT 操作中为空。

INSERT/UPDATE/DELETE 规则

使用这里的示例数据。

ALSO 选项
postgres=# \d emp;Table "public.emp"Column  |         Type          | Collation | Nullable | Default
----------+-----------------------+-----------+----------+---------empno    | integer               |           | not null |ename    | character varying(10) |           |          |job      | character varying(9)  |           |          |mgr      | integer               |           |          |hiredate | character varying(10) |           |          |sal      | numeric(7,2)          |           |          |comm     | numeric(7,2)          |           |          |deptno   | integer               |           | not null |create table emp_log(empno integer, action varchar(10));

INSERT/UPDATE/DELETE rule示例:

create or replace rule r_ins_emp
as on INSERT to emp
DO ALSO
insert into emp_log values (NEW.empno, 'INSERT');create or replace rule r_updt_emp
as on UPDATE to emp
DO ALSO
insert into emp_log values (NEW.empno, 'UPDATE');create or replace rule r_del_emp
as on DELETE to emp
DO ALSO
insert into emp_log values (OLD.empno, 'DELETE');postgres=# select * from emp_log;empno | action
-------+--------
(0 rows)postgres=# INSERT INTO EMP VALUES (7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000,NULL,10);
INSERT 0 1
postgres=# INSERT INTO EMP VALUES (7698,'BLAKE','MANAGER',7839,'1-MAY-81',2850,NULL,30);
INSERT 0 1
postgres=# select * from emp_log;empno | action
-------+--------7839 | INSERT7698 | INSERT
(2 rows)postgres=# delete from emp where empno=7698;
DELETE 1
postgres=# update emp set sal=sal*1.1 where empno=7839;
UPDATE 1
postgres=# select * from emp_log;empno | action
-------+--------7839 | INSERT7698 | INSERT7698 | DELETE7839 | UPDATE
(4 rows)

💡 每一个rule只能对应一个事件,即只能为UPDATE,INSERT或DELETE之一 加上 WHERE条件。

💡 规则总是在事件发生之前执行。

INSTEAD 选项
create or replace rule r_large_emp
as on INSERT to emp
where NEW.empno between 10000 and 100000
DO INSTEAD
insert into emp_log values (NEW.empno, 'INSTEAD');postgres=# INSERT INTO EMP VALUES (77820,'CLARK','MANAGER',7839,'9-JUN-81',2450,NULL,10);
INSERT 0 0
postgres=# select * from emp_log;empno | action
-------+---------7839 | INSERT7698 | INSERT7698 | UPDATE7839 | UPDATE77820 | INSERT77820 | INSTEAD
(6 rows)

也可以什么都不做:

create or replace rule r_large_emp
as on INSERT to emp
where NEW.empno between 10000 and 100000
DO INSTEAD NOTHING;

管理 PostgreSQL 中的触发器

如果说rule是事件处理程序,则触发器是更复杂的事件处理程序。
触发器可以处理以下的时间:

  • BEFORE INSERT/UPDATE/DELETE/TRUNCATE
  • AFTER INSERT/UPDATE/DELETE/TRUNCATE
  • INSTEAD OF INSERT/UPDATE/DELETE

触发器语法

这里说明了rule和trigger的区别:

对于两者均可实现的功能,哪种方式更佳取决于数据库的使用情况。触发器会针对每个受影响的行触发一次。规则会修改查询或生成额外的查询。因此,如果一条语句影响多行,则发出一条额外命令的规则可能比针对每一行都调用且必须多次重新确定操作的触发器更快。然而,触发器方法在概念上比规则方法简单得多,新手也更容易上手。

trigger的语法和示例可参见这里。

触发trigger的事件可以是:

  • INSERT
  • UPDATE [ OF column_name [, … ] ]
  • DELETE
  • TRUNCATE

💡 如果表中的同一事件上同时存在触发器和规则,则规则始终在触发器之前触发。
💡 如果表中的同一事件上有多个触发器,则它们按字母顺序执行。

插入和更新触发器

先创建示例表:

CREATE TABLE emp (empno INTEGER PRIMARY KEY,ename TEXT,job TEXT,salary NUMERIC
);CREATE TABLE emp_change_log (id SERIAL PRIMARY KEY,empno INTEGER,column_name TEXT,old_value TEXT,new_value TEXT,changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

创建trigger function:

CREATE OR REPLACE FUNCTION log_emp_change()
RETURNS TRIGGER AS $$
BEGIN-- 检查 enameIF NEW.ename IS DISTINCT FROM OLD.ename THENINSERT INTO emp_change_log(empno, column_name, old_value, new_value)VALUES (OLD.empno, 'ename', OLD.ename::TEXT, NEW.ename::TEXT);END IF;-- 检查 jobIF NEW.job IS DISTINCT FROM OLD.job THENINSERT INTO emp_change_log(empno, column_name, old_value, new_value)VALUES (OLD.empno, 'job', OLD.job::TEXT, NEW.job::TEXT);END IF;-- 检查 salaryIF NEW.salary IS DISTINCT FROM OLD.salary THENINSERT INTO emp_change_log(empno, column_name, old_value, new_value)VALUES (OLD.empno, 'salary', OLD.salary::TEXT, NEW.salary::TEXT);END IF;RETURN NEW;
END;
$$ LANGUAGE plpgsql;

此trigger function可同时用于INSERT和UPDATE。

创建trigger:

CREATE TRIGGER emp_update_trigger
AFTER UPDATE ON emp
FOR EACH ROW
WHEN (OLD.* IS DISTINCT FROM NEW.*)
EXECUTE FUNCTION log_emp_change();CREATE TRIGGER emp_insert_trigger
AFTER INSERT ON emp
FOR EACH ROW
EXECUTE FUNCTION log_emp_change();

测试:

INSERT INTO emp VALUES (1, 'Alice', 'Developer', 5000);
update emp set salary=salary*1.1 where ename = 'Alice';postgres=# select * from emp_change_log;id | empno | column_name | old_value | new_value |         changed_at
----+-------+-------------+-----------+-----------+----------------------------1 |       | ename       |           | Alice     | 2025-06-20 10:22:34.3332652 |       | job         |           | Developer | 2025-06-20 10:22:34.3332653 |       | salary      |           | 5000      | 2025-06-20 10:22:34.3332654 |     1 | salary      | 5000      | 5500.0    | 2025-06-20 10:24:01.273466
(4 rows)

TG_OP 变量

TG_OP指触发触发器的操作:INSERT、UPDATE、DELETE 或 TRUNCATE。

实际上还有很多TG_开头的变量,详见这里。同时提供了一个例子:

CREATE TABLE emp (empname           text NOT NULL,salary            integer
);CREATE TABLE emp_audit(operation         char(1)   NOT NULL,stamp             timestamp NOT NULL,userid            text      NOT NULL,empname           text      NOT NULL,salary            integer
);CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$BEGIN---- Create a row in emp_audit to reflect the operation performed on emp,-- making use of the special variable TG_OP to work out the operation.--IF (TG_OP = 'DELETE') THENINSERT INTO emp_audit SELECT 'D', now(), current_user, OLD.*;ELSIF (TG_OP = 'UPDATE') THENINSERT INTO emp_audit SELECT 'U', now(), current_user, NEW.*;ELSIF (TG_OP = 'INSERT') THENINSERT INTO emp_audit SELECT 'I', now(), current_user, NEW.*;END IF;RETURN NULL; -- result is ignored since this is an AFTER triggerEND;
$emp_audit$ LANGUAGE plpgsql;CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON empFOR EACH ROW EXECUTE FUNCTION process_emp_audit();

测试:

INSERT INTO emp VALUES ('Alice', 5000);
update emp set salary = 5500 where empname = 'Alice';
delete from emp;postgres=# select * from emp_audit;operation |           stamp            |  userid  | empname | salary
-----------+----------------------------+----------+---------+--------I         | 2025-06-20 10:35:23.803959 | postgres | Alice   |   5000U         | 2025-06-20 10:35:23.806063 | postgres | Alice   |   5500D         | 2025-06-20 10:35:23.807913 | postgres | Alice   |   5500
(3 rows)

事件触发器

根据文档:

与附加到单个表并仅捕获 DML 事件的常规触发器不同,事件触发器是特定数据库的全局触发器,并且能够捕获 DDL 事件。
与常规触发器一样,事件触发器可以使用任何包含事件触发器支持的过程语言或 C 语言编写,但不能使用纯 SQL 编写。

完整的DDL时间支持参见这里。还包括数据库登录。

事件触发器示例

这是官网提供的示例,禁止执行任何DDL命令:

CREATE OR REPLACE FUNCTION abort_any_command()RETURNS event_triggerLANGUAGE plpgsqlAS $$
BEGINRAISE EXCEPTION 'command % is disabled', tg_tag;
END;
$$;CREATE EVENT TRIGGER abort_ddl ON ddl_command_startEXECUTE FUNCTION abort_any_command();

验证你的知识

  • OLD,NEW表示什么?
  • 我们可以使用规则在单个事务中对两个表执行 INSERT 吗?
  • 我们可以使用触发器来完成所有根据规则所做的事情吗?
  • 我们能否知道触发器是由哪个DML语句触发吗?
  • 我们能否编写一个审计程序来通知我们何时执行了DDL?

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

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

相关文章

信创国产化替代中的开发语言选择分析

在信息技术应用创新(信创)国产化替代过程中,选择合适的开发语言至关重要。以下是适合信创环境的开发语言及其优势分析: 主流适合信创的编程语言 1. Java 优势:跨平台特性(JVM)、丰富的生态体系、企业级应用成熟 信创适配:国内有…

Android 中 函数实现多个返回值的几种方式

在编程中,函数通常只能返回一个值。但通过使用对象封装、Pair、Triple、数组、列表或 Bundle 方式,可以轻松地返回多个值。 1、对象封装方式 创建数据类来封装需要返回的多个值。 data class Result(val code: Int, val message: String)fun getMultiV…

Leetcode百题斩-DP

又到了最好玩的dp了,各种玄学转移也算是其乐无穷。前段时间刚做的LCA正是这种题的小试牛刀,如果当时就把这个专题刷完了,或许我现在已经从西溪园区跑到云谷园区了。 不过,恐怖如斯的dp专题居然只给了一道hard,基本也没…

策略模式与工厂模式的黄金组合:从设计到实战

策略模式和工厂模式是软件开发中最常用的两种设计模式,当它们结合使用时,能产生11>2的效果。本文将通过实际案例,阐述这两种模式的协同应用,让代码架构更优雅、可维护性更强。 一、为什么需要组合使用? 单独使用的…

SAP PP模块与MM模块作用详解

SAP PP模块与MM模块作用详解 一、PP模块(Production Planning)—— 生产计划与执行中枢 核心作用:将销售需求转化为可执行的生产指令,管控从计划到完工的全过程。 关键功能 功能说明业务价值主数据管理维护BOM(物料…

Linux tcp_info:监控TCP连接的秘密武器

深入解析 Linux tcp_info:TCP 状态的实时监控利器 在开发和运维网络服务时,我们常常遇到这些问题: 我的 TCP 连接为什么速度慢?是发生了重传,还是窗口太小?拥塞控制到底有没有生效? 这些问题…

CVE-2015-5531源码分析与漏洞复现(Elasticsearch目录遍历漏洞)

概述 漏洞名称:Elasticsearch 快照API目录遍历漏洞 CVE 编号:CVE-2015-5531 CVSS 评分:7.5 影响版本: Elasticsearch 1.0.0–1.6.0(1.5.1及以前版本无需配置即可触发;1.5.2–1.6.0需配置path.repo&#xf…

HexHub开发运维利器Database, Docker, SSH, SFTP

支持隧道,SFTP,X11转发,跳板机,分屏广播输入,LRZSZ,TRZSZ,SCP 分屏广播输入 管理多台服务器,更快一步 支持多种文件传输协议 支持跨服务器文件传输,使用复制粘贴即可进…

2025年教育、心理健康与信息管理国际会议(EMHIM 2025)

2025 2nd International Conference on Education, Mental Health, and Information Management 一、大会信息 会议简称:EMHIM 2025 大会地点:中国三亚 收录检索:提交Ei Compendex,CPCI,CNKI,Google Scholar等 二、会议简介 第二届教…

数字孪生技术为UI前端注入新活力:实现智能化交互新体验

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 在数字化转型的深水区,数字孪生技术正以破竹之势重构 UI 前端的技术逻辑与交互范式…

组件协作模式

目录 “组件协作”模式模板方法模式动机模式定义结构要点总结 “组件协作”模式 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”。“组件协作”模式通过晚期绑定,实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。典型模式&a…

Docker 运行RAGFlow 搭建RAG知识库

借鉴视频:DeepSeek 10分钟完全本地部署 保姆级教程 断网运行 无惧隐私威胁 大语言模型 CPU GPU 混合推理32B轻松本地部署!DeepSeek模拟王者!!_哔哩哔哩_bilibili 借鉴博客:RAGFlow搭建全攻略:从入门到精通…

python编写脚本每月1号和15号执行一次将TRX是否强更发送到钉钉

编写脚本 import requests import json import time import hmac import hashlib import base64 import urllib.parse# 1. 配置钉钉机器人 webhook "https://oapi.dingtalk.com/robot/send?access_tokenXXXXXX" secret "XXXXXXXX" # 如果没有加签验…

Linux-系统管理

[rootlocalhost ~]# lscpu //查看cpu [rootlocalhost etc]# cat /etc/redhat-release //查看当前目录的版本信息 [rootlocalhost ~]# ifconfig //查看当前激活的网卡信息 [rootlocalhost ~]# ifconfig ens33 192.168.1.10 //给网卡配置临时地址 [rootlocalhost ~]# hostnam…

【Spring】系统化的 Spring Boot 全栈学习教程,涵盖基础配置、核心功能、进阶实战及文档自动生成

这里写目录标题 🛠️ **一、环境搭建与项目创建**1. 开发环境准备2. 创建第一个项目(Spring Initializr) 🚀 **二、核心功能开发**1. RESTful API 开发2. 数据持久化(Spring Data JPA)3. 配置文件多环境切换…

Discrete Audio Tokens: More Than a Survey

文章目录 模型设计的考虑量化的方式:比特率:Fixed vs. Adaptive Bitrate码本内容设计的考虑Streamability. 模型评估Reconstruction Evaluation and Complexity Analysis.识别和生成任务(SE, SR)Acoustic Language Modeling.Music Generation…

设计在线教育项目核心数据库表

1 在线教育项目核心数据库表设计-ER图 简介:设计在线教育的核心库表结构 在线教育站点速览 xdclass.net ER图知识回顾: 实体对象:矩形属性:椭圆关系:菱形 核心库表 videochapterepisodeuservideo_ordervideo_banner…

【音视频】Ubuntu下配置ffmpeg库

一、下载预编译的库 在github上可以找到编译好的ffmpeg,多个版本的都有,这里我下载ffmpeg编译好的动态库 仓库链接:(https://github.com/BtbN/FFmpeg-Builds/releases 下载后解压得到 二、配置环境变量 打开.bashrc配置文件,添…

equine在神经网络中建立量化不确定性

​一、软件介绍 文末提供程序和源码下载 众所周知,用于监督标记问题的深度神经网络 (DNN) 可以在各种学习任务中产生准确的结果。但是,当准确性是唯一目标时,DNN 经常会做出过于自信的预测,并且无论测试数…

C++动态链接库之非托管封装Invoke,供C#/C++ 等编程语言使用,小白教程——C++动态链接库(一)

目录: 一、前言及背景1.1需求描述1.2应用背景 二、编程基础知识2.1非托管方式交互逻辑2.2该方式下C 与C# 数据转换对应2.3VS工程下的注意点2.4C封装接口2.4.1 __declspec(dllexport) 方式2.4.2 .def 文件方式2.4.3结合使用(高级) 2.5C# 封装接…