MySQL触发器终极指南:从入门到精通
引言
在处理关系型数据库和结构化查询语言(SQL)时,大多数数据操作是通过显式执行的查询操作来实现的,例如SELECT
、INSERT
或UPDATE
。
然而,SQL数据库还可以通过触发器(Triggers)自动执行预定义的操作,每当发生特定事件时。例如,您可以使用触发器保留所有DELETE
语句的审计日志,或者在每次更新或追加行到表时自动更新聚合统计摘要。
在本教程中,您将使用不同的SQL触发器来自动执行在行插入、更新或删除时进行的操作。
先决条件
要按照本指南操作,您需要一台运行基于SQL的关系数据库管理系统(RDBMS)的计算机。本指南中的指令和示例是在以下环境下验证的:
- 一台运行 Ubuntu 20.04 的服务器,拥有具备管理权限的非root用户,并配置了UFW防火墙,具体请参考我们的 Ubuntu 20.04 服务器初始设置指南。
- 在服务器上安装并配置了MySQL,具体请参考 如何在 Ubuntu 20.04 上安装 MySQL。本指南已通过使用在第3步中创建的非root MySQL用户进行验证。
- 对执行
SELECT
、INSERT
、UPDATE
和DELETE
查询以操作数据库有基本的了解,具体请参考我们的 如何在 SQL 中从表中选择行、如何在 SQL 中插入数据、如何在 SQL 中更新数据 和 如何在 SQL 中删除数据 指南。 - 对使用嵌套查询有基本的了解,具体请参考我们的 如何在 SQL 中使用嵌套查询 指南。
- 对使用聚合数学函数有基本的了解,具体请参考我们的 如何在 SQL 中使用数学表达式和聚合函数 指南。
注意:许多关系数据库管理系统使用自己的SQL实现。尽管触发器被提及为SQL标准的一部分,但标准并未强制规定其语法或具体的实现方式。因此,它们在不同数据库中的实现方式不同。本教程中概述的命令使用MySQL数据库的语法,可能无法在其他数据库引擎上正常工作。您还需要一个带有一些已加载样本数据的数据库,以便您可以练习使用函数。我们鼓励您阅读以下“连接到MySQL并设置样本数据库”部分,了解连接到MySQL服务器以及在本指南中使用的测试数据库的创建详情。
连接到MySQL并设置一个样本数据库
在本节中,您将连接到一个MySQL服务器并创建一个示例数据库,以便您可以在接下来的几节中跟随示例进行操作。
对于本指南,您将使用一个假想的收藏品集合。您将存储关于当前拥有的收藏品的详细信息,随时保持它们的总价值可用,并确保删除一个收藏品始终留下痕迹。
如果您的SQL数据库系统在远程服务器上运行,请从您的本地机器上的SSH登录到服务器。
ssh sammy@your_server_ip
然后打开MySQL服务器提示符,将“sammy”替换为您的MySQL用户帐户的名称。
mysql -u sammy -p
创建一个名为collectibles
的数据库。
CREATE DATABASE collectibles;
如果数据库创建成功,您将收到如下输出:
Query OK, 1 row affected (0.01 sec)
要选择collectibles
数据库,请运行以下USE
语句:
USE collectibles;
您将会得到以下的输出:
Database changed
在选择数据库之后,您可以在其中创建示例表。表collectibles
将包含有关数据库中收藏品的简化数据。它将包含以下列:
name
: 此列存储每个收藏品的名称,使用varchar
数据类型,最大长度为50个字符。value
: 此列存储收藏品的市场价值,使用decimal
数据类型,小数点前最多5位,小数点后2位。
用以下命令创建示例表:
CREATE TABLE collectibles (
name varchar(50),
value decimal(5, 2)
);
如果下面的输出打印出来,那么表已经被创建了。
这是文章《如何在MySQL中使用触发器》的第2部分(共9部分)。
Query OK, 0 rows affected (0.00 sec)
下一个表将命名为collectibles_stats
,它将用于跟踪收藏品集合中所有收藏品的累计价值。该表将包含一行数据,具有以下列:
- count: 此列存储已拥有收藏品的数量,使用
INT
数据类型表示。 - value: 此列存储所有收藏品的累计价值,使用
DECIMAL
数据类型,小数点前最多5位,小数点后2位。
使用以下命令创建示例表:
CREATE TABLE collectibles_stats (
count INT,
value DECIMAL(5, 2)
);
如果出现以下输出,则表示表已成功创建。
Query OK, 0 rows affected (0.00 sec)
第三个也是最后一个表将命名为collectibles_archive
,它将跟踪所有从收藏中移除的藏品,以确保它们永远不会丢失。它将保存与collectibles
表类似的数据,但增加了移除日期。它使用以下列:
- name: 此列存储每个已移除收藏品的名称,使用
VARCHAR
数据类型,最大长度为50个字符。 - value: 此列存储删除时收藏品的市场价值,使用
DECIMAL
数据类型,小数点前最多5位,小数点后2位。 - removed_on: 此列存储每个已归档收藏品的删除日期和时间,使用
TIMESTAMP
数据类型,默认值为NOW()
,表示当新行插入此表时的当前日期和时间。
使用以下命令创建示例表:
CREATE TABLE collectibles_archive (
name VARCHAR(50),
value DECIMAL(5, 2),
removed_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
如果打印出以下输出,说明表已创建:
Query OK, 0 rows affected (0.00 sec)
随后,通过运行以下INSERT INTO
操作,将collectibles_stats
表加载到空collectibles
集合的初始状态。
INSERT INTO collectibles_stats SELECT COUNT(name), SUM(value) FROM collectibles;
使用INSERT INTO
操作将向collectibles_stats
添加一行,其中的值是使用聚合函数计算得出的,以对collectibles
表中的所有行进行计数,并使用value
列和SUM
函数计算所有收藏品的总价值。下面的输出表明已添加了一行。
Query OK, 1 row affected (0.002 sec) Records: 1 Duplicates: 0 Warnings: 0
你可以通过在表上执行SELECT
语句来验证这一点。
SELECT * FROM collectibles_stats;
由于数据库中尚无可收集的物品,因此初始物品数量为0,累计价值为NULL
。
+-------+-------+
| count | value |
+-------+-------+
| 0 | NULL |
+-------+-------+
1 row in set (0.000 sec)
有了这些,你就可以继续阅读本指南并开始在MySQL中使用触发器了。
理解触发器
如何在MySQL中使用触发器(第3部分,共9部分)
触发器是针对特定表定义的语句,当表中发生指定事件时,由数据库自动执行。触发器可用于确保每次在特定表上执行某个语句时,一些操作将始终被执行,而无需数据库用户手动干预。
每个与表关联的触发器都有一个用户定义的名称和一对条件,这些条件指示数据库引擎何时执行触发器。这些条件可以分为两个不同的类别:
- 数据库事件(Database event): 触发器可以在对表执行
INSERT
、UPDATE
或DELETE
语句时被执行。 - 事件时间(Event time): 此外,触发器可以在相关语句执行之前(BEFORE)或之后(AFTER)执行。
将这两个条件组合在一起,总共有六种不同的触发可能性,每次满足联合条件时都会自动执行。在执行满足条件的语句之前,触发器的顺序是BEFORE INSERT
、BEFORE UPDATE
和BEFORE DELETE
。可以利用这些触发器在数据被插入或更新到表中之前对其进行操作和验证,或者将删除行的详情保存用于审计或归档目的。
当满足条件的语句被执行后触发的操作有AFTER INSERT
、AFTER UPDATE
和AFTER DELETE
。这些操作可以根据语句执行后数据库的最终状态,在另一个表中更新汇总值。
为了执行诸如验证和操作输入数据或归档被删除的行等操作,数据库允许在触发器内访问数据值。对于INSERT
触发器,只能使用新插入的数据。对于UPDATE
触发器,可以访问原始数据和更新后的数据。最后,对于DELETE
触发器,只能使用原始行数据(因为没有新数据可参考)。
触发器体内可使用的数据是通过数据库中当前的OLD
记录和查询将要保存的NEW
记录公开的。您可以使用OLD.column_name
和NEW.column_name
的语法来引用单个列。
以下示例展示了用于创建新触发器的SQL语句的一般语法:
- CREATE TRIGGER trigger_name trigger_condition
- ON table_name
- FOR EACH ROW
- trigger_actions;
让我们将语法分解成更小的部分:
CREATE TRIGGER
是用于在数据库中创建新触发器的SQL语句名称。trigger_name
是触发器的用户定义名称,用于描述其作用,类似于表名和列名用于描述其含义的方式。ON table_name
告诉数据库该触发器应监控在table_name
表上发生的事件。trigger_condition
是六种可能的选择之一,定义了触发器何时运行,例如BEFORE INSERT
。FOR EACH ROW
告诉数据库触发器应针对受触发事件影响的每一行运行。一些数据库支持除FOR EACH ROW
之外的其他执行模式;然而,在MySQL中,对于导致触发器执行的语句所影响的每一行运行触发器体中的语句是唯一的选项。trigger_actions
是触发器的主体,定义了触发器执行时会发生什么。它通常是一个有效的SQL语句。可以使用BEGIN
和END
关键字将语句列表包含在一个块中,从而在触发器主体中包含多个语句以执行复杂的数据操作。然而,这超出了本教程的范围。请查阅触发器的官方文档以了解更多定义触发器所使用的语法。
在接下来的部分,您将创建在进行INSERT
和UPDATE
操作之前操作数据的触发器。
使用BEFORE INSERT
和BEFORE UPDATE
触发器来操作数据
在这一节中,您将使用触发器在执行INSERT
和UPDATE
语句之前处理数据。
在这个例子中,您将使用触发器来确保数据库中的所有可收集项都使用大写名称以保持一致。如果不使用触发器,您将需要记住为每个插入和更新语句使用大写的可收集项名称。如果您忘记了,数据库将保存原样的数据,可能导致数据集中的错误。
您将从插入一个名为“spaceship model”的示例收藏品开始,价值12.50美元。为了说明问题,项目名称将以小写字母书写。执行以下语句:
- INSERT INTO collectibles VALUES (‘spaceship model‘, 12.50);
以下信息确认物品已经被添加。
Query OK, 1 row affected (0.009 sec)
通过执行SELECT
查询您可以验证该行是否已插入。
- SELECT * FROM collectibles;
以下的输出将打印到屏幕上:
这是文章《如何在MySQL中使用触发器》的第4部分(共9部分)。
+-----------------+-------+
| name | value |
+-----------------+-------+
| spaceship model | 12.50 |
+-----------------+-------+
1 row in set (0.000 sec)
这个可收藏物品的名称以小写字母保存。
为了确保所有未来的可收藏品名称都以大写字母存储,您将创建一个BEFORE INSERT
触发器。在触发语句运行之前执行的触发器,允许您在数据传递给数据库之前对其进行操作。
执行以下语句:
- CREATE TRIGGER uppercase_before_insert BEFORE INSERT
- ON collectibles
- FOR EACH ROW
- SET NEW.name = UPPER(NEW.name);
这个命令创建了一个名为uppercase_before_insert
的触发器,它会在collectibles
表上的所有INSERT
语句执行之前被触发执行。
对于每一行插入的记录,触发器中的语句SET NEW.name = UPPER(NEW.name)
将被执行。SET
SQL命令将右侧的值赋给左侧。在这种情况下,NEW.name
表示插入语句将保存的name
列的值。通过对可收藏品的名称应用UPPER
函数并将其重新赋值给列值,您将转换将保存在数据库中的值的大小写。
注意:在运行CREATE TRIGGER
命令时,您可能会遇到类似于ERROR 1419 (HY000)
的错误消息:您没有SUPER特权,并且启用了二进制日志记录(您*可能*想使用较不安全的log_bin_trust_function_creators变量)。
从MySQL 8开始,默认情况下启用了MySQL数据库引擎的二进制日志记录,除非本地安装配置覆盖。二进制日志以保存的事件形式追踪修改数据库内容的所有SQL语句。这些日志用于数据库复制,以保持数据库副本同步,并用于时间点数据恢复。
启用二进制日志记录后,为了保证在复制环境中的数据安全性和完整性,MySQL禁止创建触发器和存储过程。了解触发器和存储过程如何影响复制超出了本指南的范围。
然而,在本地环境和学习目的下,您可以安全地覆盖MySQL防止创建触发器的方式。覆盖的设置不会被持久保存,在MySQL服务器重新启动时将返回到原始值。
要覆盖二进制日志的默认设置,请以root
身份登录MySQL并执行以下命令:
SET GLOBAL log_bin_trust_function_creators = 1;
log_bin_trust_function_creators
设置控制创建触发器和存储函数的用户是否可信,使其不会创建导致不安全事件被写入二进制日志的触发器。默认情况下,该设置的值为0
,在启用二进制日志记录的环境中,只允许超级用户创建触发器。将值更改为1
后,任何发出CREATE TRIGGER
语句的用户都被信任能够理解其影响。
更新设置后,以root
身份退出登录,以您的用户身份重新登录,并重新运行CREATE TRIGGER
语句。
要了解关于MySQL中二进制日志记录和复制以及其与触发器的关系的更多信息,请参考官方MySQL文档:二进制日志和存储程序二进制日志记录。您还可以查看我们的教程:如何在MySQL中设置复制。
在具有复制功能和严格的时间点恢复要求的生产环境中使用触发器之前,请确保您已经权衡了其对二进制日志一致性的影响。
请注意:根据您的MySQL用户权限,当执行CREATE TRIGGER
命令时可能会出现错误:ERROR 1142 (42000): TRIGGER命令被拒绝,用户'user'@'host'对表'collectibles'无权限。
要授予用户TRIGGER
权限,请登录MySQL作为root
用户并执行以下命令,将'sammy'@'localhost'
替换为所需的MySQL用户名和主机:
GRANT TRIGGER on *.* TO 'sammy'@'localhost';
FLUSH PRIVILEGES;
更新用户权限后,请注销root
用户,重新以您的用户身份登录,并重新运行CREATE TRIGGER
语句。
MySQL会打印以下消息来确认触发器是否成功创建:
Query OK, 1 row affected (0.009 sec)
现在尝试使用小写参数向INSERT
查询插入一个新的收藏品。
- INSERT INTO collectibles VALUES (‘aircraft model‘, 10.00);
再次检查collectibles
表中的结果行。
- SELECT * FROM collectibles;
以下输出将会打印到屏幕上:
+-----------------+-------+
| name | value |
+-----------------+-------+
| spaceship model | 12.50 |
| AIRCRAFT MODEL | 10.00 |
+-----------------+-------+
2 rows in set (0.000 sec)
这次,新插入的“飞机模型”名称的大小写全部为大写字母,与您尝试插入的原始值不同。触发器在后台运行,在将行保存到数据库之前转换了字母的大小写。
现在,所有新的行都由触发器保护,确保名称将以大写保存。但是,仍然可以使用UPDATE
语句保存不受限制的数据。为了使用相同效果保护UPDATE
语句,创建另一个触发器。
- CREATE TRIGGER uppercase_before_update BEFORE UPDATE
- ON collectibles
- FOR EACH ROW
- SET NEW.name = UPPER(NEW.name);
两个触发器之间的区别在于触发条件。这次是在UPDATE
之前,这意味着每次在表上执行UPDATE
语句时触发器都会执行——除了以前的触发器已经覆盖的新行外,还会影响到每次更新时的现有行。
MySQL会输出一个确认信息,表示触发器已成功创建。
Query OK, 0 rows affected (0.009 sec)
为了验证新触发器的行为,请尝试更新“太空飞船模型”的价格值。
UPDATE collectibles SET value = 15.00 WHERE name = 'spaceship model';
WHERE
子句通过名称筛选要更新的行,并且 SET
子句将值更改为 15.00。
您将收到以下输出,确认该语句已更改了一行数据。
Query OK, 1 row affected (0.002 sec) Rows matched: 1 Changed: 1 Warnings: 0
检查收藏品表中的结果行。
SELECT * FROM collectibles;
以下输出将打印到屏幕上:
+—————–+——-+
| name | value |
+—————–+——-+
| SPACESHIP MODEL | 15.00 |
| AIRCRAFT MODEL | 10.00 |
+—————–+——-+
2 rows in set (0.000 sec)
现在,除了价格通过执行的语句更新为 15.00 之外,名称现在显示为“太空飞船模型”。当您运行 UPDATE
语句时,触发器被执行,影响了更新行上的值。在保存之前,名称列被转换为大写。
在本节中,您创建了两个触发器,它们在插入和更新查询之前运行,以便在将数据保存到数据库之前对其进行格式化。在下一节中,您将使用 BEFORE DELETE
触发器将被删除的行复制到一个单独的表中以进行归档。
使用“BEFORE DELETE”触发器在删除行之前执行操作
即使您不再拥有某个物品,您可能仍希望在单独的表中保留有关已删除条目的信息。在本教程的开始,您创建了一个名为 collectibles_archive
的第二个表,用于跟踪已从收藏中删除的所有收藏品。在本节中,您将使用一个触发器来归档已删除的条目,该触发器将在执行 DELETE
语句之前执行。
通过执行下面的语句检查归档表是否完全为空。
SELECT * FROM collectibles_archive;
以下输出将打印到屏幕上,确认 collectibles_archive
表为空。
Empty set (0.000 sec)
现在,如果您对 collectibles
表发起一条删除查询,任何一行数据都可能被无痕删除。
为了解决这个问题,您将创建一个触发器,在所有对 collectibles
表的 DELETE
查询之前执行。该触发器的目的是在删除之前将删除对象的副本保存到归档表中。
运行以下命令:
CREATE TRIGGER archive_before_delete BEFORE DELETE
ON collectibles
FOR EACH ROW
INSERT INTO collectibles_archive (name, value) VALUES (OLD.name, OLD.value);
触发器被命名为 archive_before_delete
,并且在 collectibles
表上的任何 DELETE
查询之前触发。对于将要删除的每一行,将执行 INSERT
语句。然后,INSERT
语句会将一个新行插入到 collectibles_archive
表中,该行的数据值取自即将删除的 OLD
记录:OLD.name
变为 name
列,OLD.value
变为 value
列。
数据库将确认触发器的创建。
Query OK, 0 rows affected (0.009 sec)
将触发器准备好后,尝试从主要的收藏表中删除一个收藏品。
DELETE FROM collectibles WHERE name = 'SPACESHIP MODEL';
输出结果证实了查询成功运行。
Query OK, 1 row affected (0.004 sec)
现在,列出所有的收藏品。
SELECT * FROM collectibles;
以下结果将打印在屏幕上:
+—————-+——-+ | name | value | +—————-+——-+ | AIRCRAFT MODEL | 10.00 | +—————-+——-+ 1 row in set (0.000 sec)
目前只剩下飞机模型;太空船模型已被删除,不再在桌子上。不过,借助之前创建的触发器,这个删除应该会被记录在collectibles_archive表中。我们来检查一下。
执行另一个查询
- SELECT * FROM collectibles_archive;
以下结果将打印到屏幕上:
+—————–+——-+———————+ | name | value | removed_on | +—————–+——-+———————+ | SPACESHIP MODEL | 15.00 | 2022-11-20 11:32:01 | +—————–+——-+———————+ 1 row in set (0.000 sec)
通过触发器,在该表中自动记录了删除操作。姓名和数值列由被删除的行中的数据填充。第三列”removed_on”并没有在定义的触发器中显式设置,所以它会采用在表创建时决定的默认值:任何新行的创建日期。因此,通过触发器添加的每个条目都将始终附带删除日期的注释。
设置了这个触发器后,你可以确保所有的DELETE查询都会在collectibles_archive中生成一条日志记录,留下关于以前拥有的收藏品的信息。
在下一部分中,您将使用在触发语句之后执行的触发器,根据所有可收集项的汇总值更新摘要表。
使用 AFTER INSERT、AFTER UPDATE 和 AFTER DELETE 触发器来在数据操纵后执行操作。在之前的两个部分中,您使用在主语句之前执行的触发器来根据更新数据库之前的原始数据执行操作。在本节中,您将使用在主语句之后执行的触发器来更新摘要表,其中包括始终最新的计数和所有收藏品的累计价值。通过这种方式,您可以确保摘要表中的数据考虑到数据库的当前状态。
首先,检查collectibles_stats表。
- SELECT * FROM collectibles_stats;
既然您还未向该表添加信息,拥有的收藏品数量为0,因此累计价值为NULL。
+——-+——-+ | count | value | +——-+——-+ | 0 | NULL | +——-+——-+ 1 row in set (0.000 sec)
由于该表没有触发器,之前发出的用于插入和更新的查询对该表没有影响。
目标是将collectibles_stats表中的一行值设置为关于收藏品数量和总价值的最新信息。您希望确保在每次插入、更新或删除操作后,表内容都会得到更新。
您可以通过创建三个单独的触发器来实现这一点,所有触发器在相应的查询之后执行。首先,创建一个”AFTER INSERT”触发器。
- CREATE TRIGGER stats_after_insert AFTER INSERT
- ON collectibles
- FOR EACH ROW
- UPDATE collectibles_stats
- SET count = (
- SELECT COUNT(name) FROM collectibles
- ), value = (
- SELECT SUM(value) FROM collectibles
- );
触发器被命名为stats_after_insert,并将在每次向collectibles表执行INSERT查询后执行,运行触发器体中的UPDATE语句。这个UPDATE查询会影响collectibles_stats表,并将count和value列设置为嵌套查询返回的值。
- SELECT COUNT(name) FROM collectibles will get the collectibles count.
- SELECT SUM(value) FROM collectibles will get the total worth of all collectibles.
数据库将确认触发器的创建。
Query OK, 0 row affected (0.009 sec)
现在,试着将先前删除的太空飞船模型重新插入到收藏品表中,以检查摘要表是否会被正确更新。
- INSERT INTO collectibles VALUES (‘spaceship model’, 15.00);
数据库将打印以下成功消息。
这是文章《如何在MySQL中使用触发器》的第7部分(共9部分)。
Query OK, 1 row affected (0.009 sec)
您可以通过运行命令来列出所有拥有的收藏品:
- SELECT * FROM collectibles;
下面的输出将打印到屏幕上:
+-----------------+-------+
| name | value |
+-----------------+-------+
| AIRCRAFT MODEL | 10.00 |
| SPACESHIP MODEL | 15.00 |
+-----------------+-------+
2 rows in set (0.000 sec)
现在有两个值得收藏的物品,总价值为25.00。要在插入新物品后检查汇总表,请执行以下查询。
- SELECT * FROM collectibles_stats;
这次,汇总表将列出所有拥有的收藏品数量为2,累计价值为25.00,与之前的输出一致。
+-------+-------+
| count | value |
+-------+-------+
| 2 | 25.00 |
+-------+-------+
1 row in set (0.000 sec)
stats_after_insert
触发器在插入查询后运行,并使用当前数据(计数和价值)更新 collectibles_stats
表,从而统计整个收藏品的内容。统计数据包括整个收藏内容,而不仅仅是最后一次插入。由于收藏现在包含飞机和太空船模型两个物品,汇总表列出了两个物品及它们的总价值。此时,将任何新的收藏物品添加到 collectibles
表都将正确更新汇总表的值。
然而,更新现有物品或删除收藏品不会对汇总产生任何影响。为了填补这个空白,您将创建两个额外的触发器,执行相同的操作,但由不同的事件触发。
- CREATE TRIGGER stats_after_update AFTER UPDATE
- ON collectibles
- FOR EACH ROW
- UPDATE collectibles_stats
- SET count = (
- SELECT COUNT(name) FROM collectibles
- ), value = (
- SELECT SUM(value) FROM collectibles
- );
- CREATE TRIGGER stats_after_delete AFTER DELETE
- ON collectibles
- FOR EACH ROW
- UPDATE collectibles_stats
- SET count = (
- SELECT COUNT(name) FROM collectibles
- ), value = (
- SELECT SUM(value) FROM collectibles
- );
您现在已经创建了两个新触发器:stats_after_update
和 stats_after_delete
。每当您在 collectibles
表上运行 UPDATE
或 DELETE
语句时,这两个触发器将在 collectible_stats
表上执行。
那些触发器的成功创建将打印以下输出:
Query OK, 0 row affected (0.009 sec)
现在,更新一件收藏品的价格值。
- UPDATE collectibles SET value = 25.00 WHERE name = ‘AIRCRAFT MODEL’;
WHERE
子句根据名称过滤要更新的行,SET
子句将值更改为25.00。
输出结果证实该语句改变了一行数据。
这是文章《如何在MySQL中使用触发器》的第8部分(共9部分)。
Query OK, 1 row affected (0.002 sec) Rows matched: 1 Changed: 1 Warnings: 0
更新后,请再次检查摘要表的内容。
- SELECT * FROM collectibles_stats;
现在的价值显示为40.00,这是更新后的正确价值。
+——-+——-+
| count | value |
+——-+——-+
| 2 | 40.00 |
+——-+——-+
1 row in set (0.000 sec)
最后一步是确保摘要表能够正确反映删除收藏品的情况。请尝试使用以下语句删除飞机模型。
- DELETE FROM collectibles WHERE name = ‘AIRCRAFT MODEL’;
以下输出证实了查询成功运行:
Query OK, 1 row affected (0.004 sec)
现在,列出所有的收藏品。
- SELECT * FROM collectibles;
以下输出将打印到屏幕上:
+—————–+——-+
| name | value |
+—————–+——-+
| SPACESHIP MODEL | 15.00 |
+—————–+——-+
1 row in set (0.000 sec)
现在只剩下太空飞船模型。接下来,检查摘要表中的数值。
- SELECT * FROM collectibles_stats;
以下输出将打印:
+——-+——-+
| count | value |
+——-+——-+
| 1 | 15.00 |
+——-+——-+
1 row in set (0.000 sec)
计数列现在显示主表中只有一个收藏品。总价值为15.00,与太空飞船模型的价值相匹配。
在插入、更新和删除查询之后,这三个触发器共同工作,以使摘要表与完整的收藏品列表保持同步。
在下一部分中,您将学习如何操作数据库上现有的触发器。
列出和删除触发器
在之前的章节中,您创建了新的触发器。由于触发器是在数据库上定义的命名对象,与表格类似,因此您可以在需要时列出它们并进行操作。
要列出所有触发器,请执行“SHOW TRIGGERS”语句。
- SHOW TRIGGERS;
输出将包括所有触发器,包括它们的名称、触发事件(在语句执行之前或之后),以及作为触发器主体一部分的语句和触发器定义的其他详细信息。
+————————-+——–+————–+——–(…)+——–+(…)
| Trigger | Event | Table | Statement | Timing |(…)
+————————-+——–+————–+——–(…)+——–+(…)
| uppercase_before_insert | INSERT | collectibles | SET (…) | BEFORE |(…)
| stats_after_insert | INSERT | collectibles | UPDATE (…) | AFTER |(…)
| uppercase_before_update | UPDATE | collectibles | SET (…) | BEFORE |(…)
| stats_after_update | UPDATE | collectibles | UPDATE (…) | AFTER |(…)
| archive_before_delete | DELETE | collectibles | INSERT (…) | BEFORE |(…)
| stats_after_delete | DELETE | collectibles | UPDATE (…) | AFTER |(…)
+————————-+——–+————–+——–(…)+——–+(…)
6 rows in set (0.001 sec)
要删除现有触发器,可以使用DROP TRIGGER
SQL语句。也许您不再希望对收藏品名称强制使用大写字母,因此不再需要uppercase_before_insert
和uppercase_before_update
触发器。执行以下命令来删除这两个触发器:
- DROP TRIGGER uppercase_before_insert;
- DROP TRIGGER uppercase_before_update;
对于这两个命令,MySQL会返回一个成功的消息。
Query OK, 0 rows affected (0.004 sec)
现在,既然两个触发器都已移除,让我们新增一个名称为小写字母的可收集物品。
- INSERT INTO collectibles VALUES (‘ship model‘, 10.00);
数据库将确认插入。
Query OK, 1 row affected (0.009 sec)
您可以通过执行SELECT查询来验证是否已成功插入该行。
- SELECT * FROM collectibles;
以下输出将显示在屏幕上。
+—————–+——-+
| name | value |
+—————–+——-+
| SPACESHIP MODEL | 15.00 |
| ship model | 10.00 |
+—————–+——-+
2 rows in set (0.000 sec)
新添加的可收集品名称是小写字母。由于名称与原始输出保持不变,您已确认先前用于转换字母大小写的触发器已不再生效。
现在您已经了解了如何通过名称列举和删除触发器。
结论
通过遵循本指南,您学会了什么是SQL触发器以及如何在MySQL中使用它们在插入和更新查询之前操作数据。您学会了如何使用BEFORE DELETE
触发器将被删除的行存档到一个单独的表中,以及如何使用AFTER
语句触发器保持摘要数据实时更新。
您可以使用函数将部分数据处理和验证工作交给数据库引擎,从而确保数据的完整性,或者向日常数据库用户隐藏某些数据库行为。本教程仅介绍了使用触发器实现此目的的基本知识。您可以构建包含多个语句并使用条件逻辑执行更精细操作的复杂触发器。要了解更多相关内容,请参考MySQL关于触发器的官方文档。
如果您想了解更多关于SQL语言及其不同概念的知识,我们鼓励您查阅《如何使用SQL系列》中的其他指南。