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
英文地址,請注明出處:http://en.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# 封裝接…