想在PostgreSQL里搞个触发器,你得先搞清楚下面这些部分:
- 触发器的名字。
- 事件类型(
INSERT、UPDATE、DELETE)。 - 执行时机(
BEFORE或AFTER)。 - 它关联的表。
- 要执行的函数(用PL/pgSQL或者别的语言写的)。
大致的命令结构是这样的:
CREATE TRIGGER 触发器名
[BEFORE | AFTER] {INSERT | UPDATE | DELETE}
ON 表名
[FOR EACH ROW | FOR EACH STATEMENT]
WHEN (条件)
EXECUTE FUNCTION 函数名();
简单触发器的例子
咱们先建个基础表students,然后加个触发器,每次插入新记录后就会触发。
先建students表:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
这里发生了啥? 我们建了个表,有id、name和last_modified字段。last_modified字段会存最后一次修改的时间。
触发器总是要配合函数用的。先写个简单函数,每次插入记录时更新last_modified字段:
CREATE OR REPLACE FUNCTION update_last_modified()
RETURNS TRIGGER AS $$
BEGIN
-- 把当前时间写进last_modified字段
NEW.last_modified := CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
这是什么魔法?
NEW—— 特殊变量,存着新行的值(用于INSERT或UPDATE事件)。CURRENT_TIMESTAMP—— 返回当前时间的函数。RETURN NEW—— 返回修改后的行,数据库会用它保存。
现在来创建触发器本体:
CREATE TRIGGER set_last_modified
AFTER INSERT
ON students
FOR EACH ROW
EXECUTE FUNCTION update_last_modified();
解释一下:
AFTER INSERT:插入新行后触发。ON students:作用于students表。FOR EACH ROW:每插入一行就触发一次。EXECUTE FUNCTION:指定要调用哪个函数。
测试触发器效果
来看看触发器到底咋样:
INSERT INTO students (name) VALUES ('Alice');
SELECT * FROM students;
你大概会看到这样的结果:
| id | name | last_modified |
|---|---|---|
| 1 | Alice | 2023-10-15 14:23:45 |
触发器自动把last_modified字段更新了。魔法?其实就是PostgreSQL的骚操作。
用WHEN加条件
有时候你不想每次都触发,而是只在特定条件下才触发。就得用WHEN关键字。
比如说,咱们只想让触发器在名字是"Alice"的学生时才触发。改一下触发器:
CREATE OR REPLACE FUNCTION update_last_modified_condition()
RETURNS TRIGGER AS $$
BEGIN
NEW.last_modified := CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_last_modified_condition
AFTER INSERT
ON students
FOR EACH ROW
WHEN (NEW.name = 'Alice')
EXECUTE FUNCTION update_last_modified_condition();
现在,只有名字是"Alice"的学生,last_modified字段才会被更新。
来试试:
INSERT INTO students (name) VALUES ('Alice');
INSERT INTO students (name) VALUES ('Bob');
SELECT * FROM students;
结果:
| id | name | last_modified |
|---|---|---|
| 1 | Alice | 2023-10-15 14:30:00 |
| 2 | Bob | (NULL) |
注意: "Bob"的last_modified字段是空的,因为触发器没触发。
触发器和函数的关系:EXECUTE FUNCTION
函数就是触发器的核心。没有函数,触发器啥也干不了。PostgreSQL里你可以用PL/pgSQL写函数,也可以用Python、C等别的语言。
来个PL/pgSQL函数的例子。
我们写个函数,每次有变化就往 表里记一笔。
先建 表:
CREATE TABLE audit_log (
id SERIAL PRIMARY KEY,
operation TEXT NOT NULL,
student_id INTEGER NOT NULL,
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
然后写函数:
CREATE OR REPLACE FUNCTION log_insert()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (operation, student_id)
VALUES ('INSERT', NEW.id);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
再写个触发器:
CREATE TRIGGER log_student_insert
AFTER INSERT
ON students
FOR EACH ROW
EXECUTE FUNCTION log_insert();
测试一下:
INSERT INTO students (name) VALUES ('Charlie');
SELECT * FROM audit_log;
你会看到类似这样的结果:
| id | operation | student_id | log_time |
|---|---|---|---|
| 1 | INSERT | 3 | 2023-10-15 14:35:00 |
触发器自动把新记录写进了日志表。
用触发器时的坑和注意事项
错误:没有函数。 如果你想创建触发器但没写函数,PostgreSQL会报错。一定要先写好函数再建触发器。
性能问题。 触发器太多或者函数太复杂,会让数据库变慢。用的时候要小心点。
递归。 如果触发器又改了自己所在的表,可能会死循环。用WHEN条件来避免这种情况。
GO TO FULL VERSION