CodeGym /课程 /SQL SELF /触发器语法基础:CREATE TRIGGER、WHEN、EXECUTE FUNCTION

触发器语法基础:CREATE TRIGGER、WHEN、EXECUTE FUNCTION

SQL SELF
第 57 级, 课程 2
可用

想在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;

这是什么魔法?

  1. NEW —— 特殊变量,存着新行的值(用于INSERT或UPDATE事件)。
  2. CURRENT_TIMESTAMP —— 返回当前时间的函数。
  3. 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条件来避免这种情况。

2
任务
SQL SELF, 第 57 级, 课程 2
已锁定
创建一个简单的日志触发器
创建一个简单的日志触发器
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION