如何在MySQL中使用触发器

引言

在处理关系型数据库和结构化查询语言(SQL)时,大多数对数据的操作是通过显式执行的查询操作来实现的,例如SELECT、INSERT或UPDATE。

然而,SQL数据库还可以通过触发器自动执行预定义的操作,每当发生特定事件时。例如,您可以使用触发器保留所有DELETE语句的审计日志,或者在每次更新或追加行到表时自动更新聚合统计摘要。

在本教程中,您将使用不同的SQL触发器来自动执行在行插入、更新或删除时进行的操作。

先决条件

要按照这个指南操作,您需要一台运行基于SQL的关系数据库管理系统(RDBMS)的计算机。本指南中的指令和示例是在以下环境下验证的:

  • A server running Ubuntu 20.04, with a non-root user with administrative privileges and a firewall configured with UFW, as described in our initial server setup guide for Ubuntu 20.04.
  • MySQL installed and secured on the server, as outlined in How To Install MySQL on Ubuntu 20.04. This guide was verified with a non-root MySQL user, created using the process described in Step 3.
  • Basic familiarity with executing SELECT, INSERT, UPDATE, and DELETE queries to manipulate data in the database as described in our How To SELECT Rows FROM Tables in SQL, How To Insert Data in SQL, How To Update Data in SQL, and How To Delete Data in SQL guides.
  • Basic familiarity with using nested queries as described in our How To Use Nested Queries in SQL guide.
  • Basic familiarity with using aggregate mathematical functions as described in our How To Use Mathematical Expressions and Aggregate Functions in SQL guide.

Note

注意:许多关系数据库管理系统使用自己的SQL实现。尽管触发器被提及为SQL标准的一部分,标准并未强制规定其语法或具体的实现方式。因此,它们在不同数据库中的实现方式不同。本教程中概述的命令使用MySQL数据库的语法,可能无法在其他数据库引擎上正常工作。

您还需要一个带有一些已加载样本数据的数据库,以便您可以练习使用函数。我们鼓励您阅读以下《连接到MySQL和设置示例数据库》部分,了解连接到MySQL服务器以及在本指南中使用的测试数据库的创建详情。

连接到MySQL并设置一个样本数据库

在本节中,您将连接到一个MySQL服务器并创建一个示例数据库,以便您可以在接下来的几节中跟随示例进行操作。

对于这个指南,你将使用一个想象中的收藏品集合。你将存储关于当前拥有的收藏品的详细信息,随时保持它们的总价值可用,并确保删除一个收藏品始终留下痕迹。

如果您的SQL数据库系统在远程服务器上运行,请从您的本地机器上的SSH登录到服务器。

  1. ssh sammy@your_server_ip

 

然后打开MySQL服务器提示符,将“sammy”替换为您的MySQL用户帐户的名称。

  1. mysql -u sammy -p

 

创建一个名为collectibles的数据库。

  1. CREATE DATABASE collectibles;

 

如果数据库创建成功,您将收到如下输出:

Output

Query OK, 1 row affected (0.01 sec)

要选择收藏品数据库,请运行以下USE语句:

  1. USE collectibles;

 

你将会得到以下的输出:

Output

Database changed

在选择数据库之后,您可以在其中创建示例表。表格collectibles将包含有关数据库中收藏品的简化数据。它将包含以下列:

  • name: This column holds the name for each collectible, expressed using the varchar data type with a maximum of 50 characters.
  • value: This column stores the collectible’s market value using the decimal data type with a maximum of 5 values before the decimal point and 2 values after it.

用以下命令创建示例表格:

  1. CREATE TABLE collectibles (
  2. name varchar(50),
  3. value decimal(5, 2)
  4. );

 

如果下面的输出打印出来,那么表已经被创建了。

Output

Query OK, 0 rows affected (0.00 sec)

下一个表将被命名为collectibles_stats,并将用于跟踪收藏品收藏中所有收藏品的累计价值。它将包含一行数据,具有以下列:

  • count: This column holds the number of owned collectibles, expressed using the int data type.
  • value: This column stores the accumulated worth of all collectibles using the decimal data type with a maximum of 5 values before the decimal point and 2 values after it.

用以下命令创建示例表:

  1. CREATE TABLE collectibles_stats (
  2. count int,
  3. value decimal(5, 2)
  4. );

 

如果出现了下面的输出,则表示表已经创建成功。

Output

Query OK, 0 rows affected (0.00 sec)

第三个也是最后一个表将被称为collectibles_archive,它将跟踪所有从收藏中删除的藏品,以确保它们永远不会消失。它将保存与collectibles表类似的数据,但加上了移除日期。它使用以下列:

  • name: This column holds the name for each removed collectible, expressed using the varchar data type with a maximum of 50 characters.
  • value: This column stores the collectible’s market value at the moment of deletion using the decimal data type with a maximum of 5 values before the decimal point and 2 values after it.
  • removed_on: This column stores the date and time of deletion for each archived collectible using the timestamp data type with the default value of NOW(), meaning the current date whenever a new row is inserted into this table.

用以下命令创建示例表:
创建样本表

  1. CREATE TABLE collectibles_archive (
  2. name varchar(50),
  3. value decimal(5, 2),
  4. removed_on timestamp DEFAULT CURRENT_TIMESTAMP
  5. );

 

如果打印出以下输出,说明表已经创建:

Output

Query OK, 0 rows affected (0.00 sec)

随后,通过运行以下INSERT INTO操作,将collectibles_stats表加载到空collectibles集合的初始状态。

  1. INSERT INTO collectibles_stats SELECT COUNT(name), SUM(value) FROM collectibles;

 

使用INSERT INTO操作将向collectibles_stats添加一行,其中的值是使用聚合函数计算得出的,以对collectibles表中的所有行进行计数,并使用value列和SUM函数计算所有收藏品的总价值。下面的输出表明已经添加了一行。

Output

Query OK, 1 row affected (0.002 sec) Records: 1 Duplicates: 0 Warnings: 0

你可以通过在表上执行SELECT语句来验证这一点。

  1. SELECT * FROM collectibles_stats;

 

由于数据库中尚无可收集的物品,因此初始物品数量为0,累计价值为空。

Output

+——-+——-+ | count | value | +——-+——-+ | 0 | NULL | +——-+——-+ 1 row in set (0.000 sec)

有了这些,你就可以继续阅读本指南并开始在MySQL中使用触发器了。

理解触发器

触发器是针对特定表格定义的语句,在表格中的指定事件发生时由数据库自动执行。触发器可用于确保在每次执行特定表格上的某个语句时,一些操作将始终被执行,而不需要数据库用户手动执行。

每个与表关联的触发器都有一个用户定义的名称和一对条件,这些条件指示数据库引擎何时执行触发器。这些条件可以分为两个不同的类别。

  • Database event: The trigger can be executed when INSERT, UPDATE, or DELETE statements are run on a table.
  • Event time: Additionally, triggers can be executed BEFORE or AFTER the statement in question.

将两个条件组合在一起,总共有六种不同的触发可能性,每次满足联合条件时会自动执行。在执行满足条件的语句之前,触发器的顺序是BEFORE INSERT、BEFORE UPDATE和BEFORE DELETE。可以利用这些触发器在数据被插入或更新到表中之前对其进行操作和验证,或者将删除行的详情保存用于审计或档案目的。

当满足条件的语句被执行后触发的操作有“插入后”、“更新后”和“删除后”。这些操作可以根据语句执行后数据库的最终状态,在另一个表中更新汇总值。

为了执行诸如验证和操作输入数据或存档被删除的行等操作,数据库允许在触发器内访问数据值。对于INSERT触发器,只能使用新插入的数据。对于UPDATE触发器,可以访问原始数据和更新后的数据。最后,对于DELETE触发器,只能使用原始行数据(因为没有新数据可参考)。

触发器体内可使用的数据是通过数据库中当前的OLD记录和查询将要保存的NEW记录公开的。您可以使用OLD.column_name和NEW.column_name的语法来引用单个列。

以下示例展示了用于创建新触发器的SQL语句的一般语法。

  1. CREATE TRIGGER trigger_name trigger_condition
  2. ON table_name
  3. FOR EACH ROW
  4. trigger_actions;

 

让我们将语法分解成更小的部分:

  • CREATE TRIGGER is the name of the SQL statement used to create a new trigger in the database.
  • trigger_name is the user-defined name of the trigger, used to describe its role, similar to how table names and column names are used to describe their meaning.
  • ON table_name tells the database that the trigger should monitor events happening on the table_name table.
  • trigger_condition is one of the six possible choices defining when the trigger should run, for example, BEFORE INSERT.
  • FOR EACH ROW tells the database that the trigger should be run for each row affected by the triggering event. Some databases support additional patterns of execution other than FOR EACH ROW; however, in the case of MySQL, running the statements from the trigger body for each row affected by the statement that caused the trigger to execute is the only option.
  • trigger_actions is the trigger’s body and defines what happens when the trigger executes. It’s typically a single valid SQL statement. It is possible to include multiple statements in the trigger body to perform complex data operations using the BEGIN and END keywords to enclose the list of statements in a block. This is, however, out of the scope of this tutorial. Check out the official documentation for triggers to learn more about the syntax used to define triggers.

在接下来的部分,您将创建在进行INSERT和UPDATE操作之前操作数据的触发器。

使用BEFORE INSERT和BEFORE UPDATE触发器来操作数据。

在这一节中,您将使用触发器在执行INSERT和UPDATE语句之前处理数据。

在这个例子中,您将使用触发器来确保数据库中的所有可收集项都使用大写名称以保持一致。如果不使用触发器,您将需要记住为每个插入和更新语句使用大写的可收集项名称。如果您忘记了,数据库将保存原样的数据,可能导致数据集中的错误。

您将从插入一个名为“spaceship model”的示例收藏品开始,价值12.50美元。为了说明问题,项目名称将以小写字母书写。执行以下语句:

  1. INSERT INTO collectibles VALUES (spaceship model, 12.50);

 

以下的信息确认物品已经被添加。

Output

Query OK, 1 row affected (0.009 sec)

通过执行SELECT查询您可以验证该行是否已插入。

  1. SELECT * FROM collectibles;

 

以下的输出将打印到屏幕上:

Output

+—————–+——-+ | name | value | +—————–+——-+ | spaceship model | 12.50 | +—————–+——-+ 1 row in set (0.000 sec)

这个可收藏的物品按原样保存下来,名字只用小写字母拼写。

为了确保所有未来的可收藏品都以大写字母书写,你将创建一个BEFORE INSERT触发器。使用在触发语句运行之前执行的触发器,使你能在数据传递给数据库之前对其进行操作。

执行以下语句。

  1. CREATE TRIGGER uppercase_before_insert BEFORE INSERT
  2. ON collectibles
  3. FOR EACH ROW
  4. SET NEW.name = UPPER(NEW.name);

 

这个命令创建了一个名为uppercase_before_insert的触发器,它会在表collectibles上的所有INSERT语句执行之前被触发执行。

对于每一行插入的记录,触发器中的语句 SET NEW.name = UPPER(NEW.name) 将被执行。SET SQL 命令将右侧的值赋给左侧。在这种情况下,NEW.name 表示插入语句将保存的 name 列的值。通过对可收集的名称应用 UPPER 函数并将其重新赋值给列值,您将转换将保存在数据库中的值的大小写。

Warning

注意:在运行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中设置复制。
在具有复制功能和严格的时点恢复要求的生产环境中使用触发器之前,请确保您已经权衡了其对二进制日志一致性的影响。

Note

请注意:根据您的MySQL用户权限,当执行CREATE TRIGGER命令时可能会出现错误:ERROR 1142 (42000): TRIGGER命令被拒绝,用户’user’@’host’对表’collectibles’无权限。要授予用户TRIGGER权限,请登录MySQL作为root用户并执行以下命令,更换为所需的MySQL用户名和主机:
GRANT TRIGGER on *.* TO ‘sammy’@’localhost’;
FLUSH PRIVILEGES;

更新用户权限后,请注销root用户,重新以该用户身份登录,并重新运行CREATE TRIGGER语句。

MySQL会打印以下消息来确认触发器是否成功创建:

Output

Query OK, 1 row affected (0.009 sec)

现在尝试使用小写参数向INSERT查询插入一个新的收藏品。

  1. INSERT INTO collectibles VALUES (aircraft model, 10.00);

 

再次检查收藏品表中的结果行。

  1. SELECT * FROM collectibles;

 

以下输出将会打印到屏幕上:

Output

+—————–+——-+ | name | value | +—————–+——-+ | spaceship model | 12.50 | | AIRCRAFT MODEL | 10.00 | +—————–+——-+ 2 rows in set (0.000 sec)

这次,新插入的表单中的飞机型号的大小写全部为大写字母,与您尝试插入的表单不同。触发器在后台运行,在将行保存到数据库之前转换了字母的大小写。

现在,所有新的行都由触发器保护,确保名称将以大写保存。但是,仍然可以使用UPDATE语句保存不受限制的数据。为了使用相同效果保护UPDATE语句,创建另一个触发器。

  1. CREATE TRIGGER uppercase_before_update BEFORE UPDATE
  2. ON collectibles
  3. FOR EACH ROW
  4. SET NEW.name = UPPER(NEW.name);

 

两个触发器之间的区别在于触发条件。这次是在UPDATE之前,意味着每次在表上执行UPDATE语句时触发器都会执行 —— 除了以前的触发器已经覆盖的新行外,还会影响到每次更新时的现有行。

MySQL会输出一个确认信息,表示触发器已成功创建。

Output

Query OK, 0 row affected (0.009 sec)

为了验证新触发器的行为,请尝试更新太空船模型的价格值。

  1. UPDATE collectibles SET value = 15.00 WHERE name = spaceship model;

 

WHERE子句通过名称筛选要更新的行,并且SET子句将值更改为15.00。

您将收到以下输出,确认该语句已更改了一行数据。

Output

Query OK, 1 row affected (0.002 sec) Rows matched: 1 Changed: 1 Warnings: 0

检查收藏品表中的结果行。

  1. SELECT * FROM collectibles;

 

以下输出将打印到屏幕上:

Output

+—————–+——-+ | 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语句之前执行。

通过执行下面的语句检查归档表是否完全为空。

  1. SELECT * FROM collectibles_archive;

 

以下输出将打印到屏幕上,确认 collectibles_archive 表为空。

Output

Empty set (0.000 sec)

现在,如果你对收藏品表发起一条删除的查询,任何一行数据都可能被无痕删除。

为了解决这个问题,您将创建一个触发器,在所有对collectibles表的DELETE查询之前执行。该触发器的目的是在删除之前将删除对象的副本保存到归档表中。

运行以下命令:

  1. CREATE TRIGGER archive_before_delete BEFORE DELETE
  2. ON collectibles
  3. FOR EACH ROW
  4. 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列。

数据库将确认触发器的创建。

Output

Query OK, 0 row affected (0.009 sec)

将触发器准备好后,尝试从主要的收藏表中删除一个收藏品。

  1. DELETE FROM collectibles WHERE name = SPACESHIP MODEL;

 

输出结果证实了查询成功地运行了。

Output

Query OK, 1 row affected (0.004 sec)

现在,列出所有的收藏品。

  1. SELECT * FROM collectibles;

 

以下结果将打印在屏幕上:

Output

+—————-+——-+ | name | value | +—————-+——-+ | AIRCRAFT MODEL | 10.00 | +—————-+——-+ 1 row in set (0.000 sec)

目前只剩下飞机模型;太空船模型已被删除,不再在桌子上。不过,借助之前创建的触发器,这个删除应该会被记录在collectibles_archive表中。我们来检查一下。

执行另一个查询

  1. SELECT * FROM collectibles_archive;

 

以下结果将打印到屏幕上:

Output

+—————–+——-+———————+ | 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表。

  1. SELECT * FROM collectibles_stats;

 

既然您还未向该表添加信息,拥有的收藏品数量为0,因此累计价值为NULL。

Output

+——-+——-+ | count | value | +——-+——-+ | 0 | NULL | +——-+——-+ 1 row in set (0.000 sec)

由于该表没有触发器,之前发出的用于插入和更新的查询对该表没有影响。

目标是将collectibles_stats表中的一行值设置为关于收藏品数量和总价值的最新信息。您希望确保在每次插入、更新或删除操作后,表内容都会得到更新。

您可以通过创建三个单独的触发器来实现这一点,所有触发器在相应的查询之后执行。首先,创建一个”AFTER INSERT”触发器。

  1. CREATE TRIGGER stats_after_insert AFTER INSERT
  2. ON collectibles
  3. FOR EACH ROW
  4. UPDATE collectibles_stats
  5. SET count = (
  6. SELECT COUNT(name) FROM collectibles
  7. ), value = (
  8. SELECT SUM(value) FROM collectibles
  9. );

 

触发器被命名为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.

数据库将确认触发器的创建。

Output

Query OK, 0 row affected (0.009 sec)

现在,试着将先前删除的太空飞船模型重新插入到收藏品表中,以检查摘要表是否会被正确更新。

  1. INSERT INTO collectibles VALUES (‘spaceship model’, 15.00);

 

数据库将打印以下成功消息。

Output

Query OK, 1 row affected (0.009 sec)

您可以通过运行命令来列出所有拥有的收藏品:

  1. SELECT * FROM collectibles;

 

下面的输出将打印到屏幕上:

Output

+—————–+——-+ | name | value | +—————–+——-+ | AIRCRAFT MODEL | 10.00 | | SPACESHIP MODEL | 15.00 | +—————–+——-+ 2 rows in set (0.000 sec)

有两个值得收藏的物品总价值25.00。要在插入新物品后检查摘要表,请执行以下查询。

  1. SELECT * FROM collectibles_stats;

 

这次,汇总表将列出所有拥有的收藏品数量为2,累计价值为25.00,与之前的输出一致。

Output

+——-+——-+ | count | value | +——-+——-+ | 2 | 25.00 | +——-+——-+ 1 row in set (0.000 sec)

stats_after_insert 触发器在插入查询后运行,并使用当前数据(计数和价值)更新 collectibles_stats 表,关于整个收藏的内容进行统计。统计数据包括整个收藏内容,而不仅仅是最后一次插入。由于收藏现在包含飞机和太空船模型两个物品,摘要表列出了两个物品及它们的总价值。此时,将任何新的收藏物品添加到 collectibles 表都将正确更新摘要表的值。

然而,更新现有物品或删除收藏品不会对摘要产生任何影响。为了填补这个空白,您将创建两个额外的触发器,执行相同的操作,但由不同的事件触发。

  1. CREATE TRIGGER stats_after_update AFTER UPDATE
  2. ON collectibles
  3. FOR EACH ROW
  4. UPDATE collectibles_stats
  5. SET count = (
  6. SELECT COUNT(name) FROM collectibles
  7. ), value = (
  8. SELECT SUM(value) FROM collectibles
  9. );
  10. CREATE TRIGGER stats_after_delete AFTER DELETE
  11. ON collectibles
  12. FOR EACH ROW
  13. UPDATE collectibles_stats
  14. SET count = (
  15. SELECT COUNT(name) FROM collectibles
  16. ), value = (
  17. SELECT SUM(value) FROM collectibles
  18. );

 

您现在已经创建了两个新触发器:stats_after_update和stats_after_delete。每当您在collectibles表上运行UPDATE或DELETE语句时,这两个触发器将在collectible_stats表上执行。

那些触发器的成功创建将打印以下输出:

Output

Query OK, 0 row affected (0.009 sec)

现在,更新一件收藏品的价格值。

  1. UPDATE collectibles SET value = 25.00 WHERE name = ‘AIRCRAFT MODEL’;

 

WHERE子句根据名称过滤要更新的行,SET子句将值更改为25.00。

输出结果证实该语句改变了一行数据。

Output

Query OK, 1 row affected (0.002 sec) Rows matched: 1 Changed: 1 Warnings: 0

更新后,请再次检查摘要表的内容。

  1. SELECT * FROM collectibles_stats;

 

现在的价值列出为40.00,这是更新后的正确价值。

Output

+——-+——-+ | count | value | +——-+——-+ | 2 | 40.00 | +——-+——-+ 1 row in set (0.000 sec)

最后一步是确保摘要表能够正确反映删除可收藏品的情况。请尝试使用以下语句删除飞机模型。

  1. DELETE FROM collectibles WHERE name = ‘AIRCRAFT MODEL’;

 

以下输出证实了查询成功运行:

Output

Query OK, 1 row affected (0.004 sec)

现在,将所有的收藏品列出来。

  1. SELECT * FROM collectibles;

 

以下输出将打印到屏幕上:

Output

+—————–+——-+ | name | value | +—————–+——-+ | SPACESHIP MODEL | 15.00 | +—————–+——-+ 1 row in set (0.000 sec)

现在只剩下太空飞船模型。接下来,检查摘要表中的数值。

  1. SELECT * FROM collectibles_stats;

 

以下输出将打印:

Output

+——-+——-+ | count | value | +——-+——-+ | 1 | 15.00 | +——-+——-+ 1 row in set (0.000 sec)

计数列现在显示主表中只有一个可收集品。总价值为15.00,与太空飞船模型的价值相匹配。

在插入、更新和删除查询之后,这三个触发器共同工作,以使摘要表与完整的可收集物品列表保持同步。

在下一部分中,您将学习如何操作数据库上现有的触发器。

列出和删除触发器

在之前的章节中,您创建了新的触发器。由于触发器是在数据库上定义的被命名对象,与表格类似,因此您可以在需要时列出它们并进行操作。

要列出所有触发器,请执行”SHOW TRIGGERS”语句。

  1. SHOW TRIGGERS;

 

输出将包括所有触发器,包括它们的名称、触发事件(在语句执行之前或之后),以及作为触发器主体一部分的语句和触发器定义的其他详细信息。

Output, simplified for readability

+————————-+——–+————–+——–(…)+——–+(…) | 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触发器。执行以下命令来删除这两个触发器:

  1. DROP TRIGGER uppercase_before_insert;
  2. DROP TRIGGER uppercase_before_update;

 

对于这两个命令,MySQL会返回一个成功的消息。

Output

Query OK, 0 rows affected (0.004 sec)

现在,既然两个触发器消失了,让我们新增一个小写字母的可收集物品。

  1. INSERT INTO collectibles VALUES (ship model, 10.00);

 

数据库将确认插入。

Output

Query OK, 1 row affected (0.009 sec)

您可以通过执行SELECT查询来验证是否插入了该行。

  1. SELECT * FROM collectibles;

 

下面的输出将打印到屏幕上。

Output

+—————–+——-+ | 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系列》中的其他指南。

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds