如何使用SQL系列 之 如何在MySQL中使用触发器

引言

当使用关系型数据库和结构化查询语言(SQL)时,对数据的大多数操作都是显式执行查询的结果,例如SELECTINSERTUPDATE

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

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

前期准备

遵循这个指南,你将需要一个计算机运行一个基于sql的关系数据库管理系统(RDBMS)。本指南中的说明和示例使用以下环境进行了验证:

-基本熟悉执行SELECTINSERTUPDATEDELETE查询来操作数据库中的数据,如如何在SQL中从表中选择行,如何在SQL中插入数据,如何在SQL中更新数据,以及如何在SQL指南中删除数据所述。
-基本熟悉使用嵌套查询,如在SQL指南中如何使用嵌套查询中所述。
-基本熟悉使用聚集数学函数,如在SQL指南中如何使用数学表达式和聚集函数所述。

注意:许多RDBMS使用它们自己的SQL实现。虽然触发提到作为一个SQL标准的一部分,标准不严格执行他们的语法或实现它们的方法。因此,它们的实现在不同的数据库中是不同的。本教程中概述的命令使用MySQL数据库的语法,可能无法在其他数据库引擎上工作。

你还需要一个数据库,其中一些表加载了示例数据,这样你就可以练习使用函数。我们鼓励您通过以下连接到示例数据库MySQL和建立一个连接到MySQL服务器上部分细节,创建测试数据库在本指南中使用的例子。

连接到MySQL并设置一个示例数据库

如果SQL数据库系统运行在远程服务器上,请从本地设备SSH到服务器:

ssh sammy@your_server_ip

然后打开MySQL服务器提示符,将sammy替换为你的MySQL用户账户的名称:

mysql -u sammy -p

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

CREATE DATABASE collectibles;

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

OutputQuery OK, 1 row affected (0.01 sec)

要选择collectibles数据库,运行以下USE语句:

USE collectibles;
OutputDatabase changed

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

  • name:这一列保存了每个收藏品的名称,使用varchar数据类型表示,最多不超过50个字符。
  • value:这一列使用decimal数据类型存储收藏品的市值,小数点前的最大值为5,小数点后的最大值为2

使用下面的命令创建示例表:

CREATE TABLE collectibles (name varchar(50),value decimal(5, 2)
);

如果输出结果如下所示,说明表已经创建:

OutputQuery 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)
);

如果输出结果如下所示,说明表已经创建:

OutputQuery OK, 0 rows affected (0.00 sec)

第三张也是最后一张表叫做collectibles_archive,它将记录所有从集合中删除的收藏品,以确保它们永远不会消失。它将保存类似于collectibles表的数据,只是增加了删除日期。它使用以下列:

  • name:这一列保存了每个被移除的收藏品的名称,使用varchar数据类型表示,最多不超过50个字符。
  • value:这一列使用decimal数据类型存储收藏品删除时的市值,小数点前的值最多为5,小数点后的值最多为2
  • removed_on:这一列存储了使用默认值为NOW()timestamp数据类型删除每个存档集合的日期和时间,即每当有新行插入该表时的当前日期。

使用下面的命令创建示例表:

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

如果输出结果如下所示,说明表已经创建:

OutputQuery OK, 0 rows affected (0.00 sec)

接下来,通过运行以下INSERT INTO操作,设置collectibles_stats表:

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

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

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

你可以通过在表上执行SELECT语句来验证:

SELECT * FROM collectibles_stats;

由于数据库中还没有可收集的物品,所以初始的物品数量是0,累积的值是NULL

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

有了这些,你就可以按照本指南的其余部分开始在MySQL中使用触发器了。

了解触发器

触发器语句定义了一个特定的表,数据库会自动执行每次该表中的指定的事件发生。触发器可以用来保证每次在表上执行特定语句时,某些操作都会一致地执行,而不需要数据库用户记住手动执行这些操作。

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

  • 数据库事件:当INSERTUPDATEDELETE语句在表上运行时,可以执行触发器。
  • 事件时间:此外,触发器可以在相关语句的BEFORE11AFTER执行。

将两个条件组组合起来,总共产生6个单独的触发可能性,每次满足联合条件时自动执行这些触发可能性。在满足条件的语句执行之前发生的触发器是AFTER INSERTAFTER UPDATEAFTER DELETE。它们可用于在数据插入或更新到表中之前操作和验证数据,或用于保存已删除行的详细信息以进行审计或存档。

在满足条件的语句执行之后发生的触发器是INSERT之后、UPDATE之后和DELETE之后。这些可用于根据语句执行后数据库的最终状态更新单独表中的汇总值。

为了执行验证和操作输入数据或对删除的行进行归档等操作,数据库允许从触发器中访问数据值。对于INSERT触发器,只有新插入的数据可以使用。对于UPDATE触发器,原始数据和更新后的数据都可以访问。最后,使用DELETE触发器,只有原始行数据可以使用(因为没有新数据可引用)。

触发器主体中使用的数据暴露在数据库中当前数据的OLD记录下,以及查询将保存的数据的NEW记录下。你可以使用OLD.column_nameNEW.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语句。可以在触发器体中包含多条语句,使用BEGINEND关键字将语句列表包含在一个块中来执行复杂的数据操作。然而,这超出了本教程的范围。查看触发器的官方文档以了解有关定义触发器的语法的更多信息。

在下一节中,我们将创建在INSERTUPDATE操作之前操作数据的触发器。

使用BEFORE INSERTBEFORE UPDATE触发器操作数据

在本节中,你将使用触发器在INSERTUPDATE语句执行之前操作数据。

在这个例子中,你将使用触发器来确保数据库中的所有收藏品名称都使用大写,以保持一致性。如果不使用触发器,你将不得不记住为每个INSERTUPDATE语句使用大写的集合名称。如果你忘记了,数据库将按原样保存数据,这可能会导致数据集中出现错误。

你将从插入一个名为太空船模型的示例可收集物品开始,价值12.50。项目名称将以小写形式书写,以说明问题。执行下面的语句:

INSERT INTO collectibles VALUES ('spaceship model', 12.50);

下面的消息确认添加了该项目:

OutputQuery OK, 1 row affected (0.009 sec)

你可以通过执行SELECT查询来验证该行是否被插入:

SELECT * FROM collectibles;
Output+-----------------+-------+
| name            | value |
+-----------------+-------+
| spaceship model | 12.50 |
+-----------------+-------+
1 row in set (0.000 sec)

这个收藏品被原样保存,只是名字的拼写只有小写字母。

为了确保所有未来的收藏品都是大写的,你需要创建一个BEFORE INSERT触发器。使用触发器执行之前触发语句允许您运行操作的数据将被传递到数据库之前发生。

Run the following statement:

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

该命令创建了一个名为uppercase_before_insert的触发器,它将在名为collectibles的表上的所有INSERT语句的BEFORE执行。

触发器SET NEW.name = UPPER(NEW.name)中的语句将对每一行插入执行。SET SQL命令将右边的值赋给左边。在这种情况下,NEW.name代表插入语句将保存的name列的值。通过对集合名称应用UPPER函数并将其赋值给列值,你正在转换将保存在数据库中的值的字母大小写。

注意:当运行CREATE TRIGGER命令时,您可能会遇到类似ERROR 1419 (HY000): You do not have the SUPER privilege, and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)的错误消息。

从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 command denied to user 'user'@'host' for table 'collectibles'。要给你的用户授予TRIGGER权限,以root身份登录MySQL并执行以下命令,根据需要替换MySQL用户名和主机:

GRANT TRIGGER on *.* TO 'sammy'@'localhost';
FLUSH PRIVILEGES;

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

MySQL将打印以下消息,以确认触发器已成功创建:

OutputQuery OK, 1 row affected (0.009 sec)

现在尝试插入一个新的收藏品,同样使用小写参数给INSERT查询:

INSERT INTO collectibles VALUES ('aircraft model', 10.00);

再一次检查collectibles表中的结果行:

SELECT * FROM collectibles;
Output+-----------------+-------+
| name            | value |
+-----------------+-------+
| spaceship model | 12.50 |
| AIRCRAFT MODEL  | 10.00 |
+-----------------+-------+
2 rows in set (0.000 sec)

然而,这一次,新的条目显示的是AIRCRAFT MODEL,所有字母都是大写——与你试图插入的条目不同。触发器在后台运行,并在行保存到数据库之前转换字母大小写。

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

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

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

MySQL会输出一个确认,已经成功地创建了触发器:

OutputQuery OK, 0 row affected (0.009 sec)

为了验证新触发器的行为,尝试更新spaceship model的价格:

UPDATE collectibles SET value = 15.00 WHERE name = 'spaceship model';

WHERE子句过滤要更新的行,SET子句将值更改为15.00

你会收到以下输出,确认这条语句只修改了一行:

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

查看collectibles表中的结果行:

SELECT * FROM collectibles;
Output+-----------------+-------+
| name            | value |
+-----------------+-------+
| SPACESHIP MODEL | 15.00 |
| AIRCRAFT MODEL  | 10.00 |
+-----------------+-------+
2 rows in set (0.000 sec)

现在,除了价格被执行的语句更新到15.00之外,名称现在是SPACESHIP MODEL。当你运行UPDATE语句时,触发器被执行,影响了更新行的值。name列在保存之前被转换为大写。

在本节中,我们创建了两个在INSERTUPDATE查询之前工作的触发器,它们在将数据保存到数据库之前使数据符合规范。在下一节中,您将使用BEFORE DELETE触发器将删除的行复制到单独的表中进行归档。

使用BEFORE DELETE触发器在删除行之前执行操作

即使你不再拥有某项,也可能希望在另一张表中留下一条关于删除的记录。在本教程开始时,你创建了第二个名为collectibles_archive的表,用于记录从集合中删除的所有收藏品。在本节中,你将使用触发器将删除的条目归档,该触发器将在DELETE语句之前执行。

执行以下语句检查归档表是否为空:

SELECT * FROM collectibles_archive;

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

OutputEmpty set (0.000 sec)

现在,如果你对collectibles表执行DELETE查询,表中的任何行都可能被删除而不会被跟踪。

为了解决这个问题,你需要创建一个触发器,它会在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表的BEFORE中执行任何DELETE查询。对于将要被删除的每一行,INSERT语句将被执行。反过来,INSERT语句将从OLD记录中获取的数据值插入到collectibles_archive表中:OLD.name变成了name列,OLD.value变成了value列。

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

OutputQuery OK, 0 row affected (0.009 sec)

有了触发器之后,试着从主要的收藏品表中删除收藏品:

DELETE FROM collectibles WHERE name = 'SPACESHIP MODEL';
OutputQuery OK, 1 row affected (0.004 sec)

现在,列出所有收藏品:

SELECT * FROM collectibles;
Output+----------------+-------+
| name           | value |
+----------------+-------+
| AIRCRAFT MODEL | 10.00 |
+----------------+-------+
1 row in set (0.000 sec)

现在只剩下AIRCRAFT MODELSPACESHIP MODEL已被删除,不再是在桌上。但是,使用之前创建的触发器,此删除应该注册在collectibles_archive表中。我们来检查一下。

执行另一个查询:

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)

该删除由触发器自动记录在该表中。namevalue列已经填充了被删除行的数据。第三列,removed_on,没有通过定义的触发器显式设置,所以它使用创建表期间决定的默认值:任何新行创建的日期。因此,在触发器的帮助下添加的每个条目都会标注删除日期。

有了这个触发器,你现在可以确定所有的DELETE查询都会在collectibles_archive中产生一个日志条目,留下关于之前拥有的收藏品的信息。

在下一节中,您将使用在触发语句之后执行的触发器,使用基于所有收集的聚合值更新汇总表。

使用AFTER INSERTAFTER UPDATEAFTER DELETE触发器在数据操作之后执行操作

在前面两节中,我们使用了在main语句之前执行的触发器,在更新数据库之前执行基于原始数据的操作。在本节中,您将使用始终最新的计数和所有集合的累积值来更新汇总表,使用在预期语句之后执行的触发器。这样,您将确保汇总表数据考虑到数据库的当前状态。

首先检查collectibles_stats表:

SELECT * FROM collectibles_stats;

由于您还没有向此表添加信息,因此拥有的收藏品数量为0,因此累计值为NULL

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

因为这张表没有触发器,所以之前发布的插入和更新收藏品的查询不会影响这张表。

我们的目标是在collectibles_stats表的单行中设置值,以显示有关收藏品数量和总价值的最新信息。你希望确保表的内容在每次INSERTUPDATEDELETE操作后都被更新。

您可以通过创建三个单独的触发器来实现这一点,它们都在相应的查询之后执行。首先,创建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,它将在INSERT查询collectibles表的之后执行,并在触发器体中运行UPDATE语句。UPDATE查询会影响collectibles_stats,并将countvalue列设置为嵌套查询返回的值:

  • SELECT COUNT(name) FROM collectibles会得到收藏品的数量
  • SELECT SUM(value) FROM collectibles将获得所有收藏品的总价值

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

OutputQuery OK, 0 row affected (0.009 sec)

现在,尝试将之前删除的spaceship model重新插入到collections表中,以检查汇总表是否会正确更新:

INSERT INTO collectibles VALUES ('spaceship model', 15.00);
OutputQuery OK, 1 row affected (0.009 sec)

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

SELECT * FROM collectibles;
Output+-----------------+-------+
| 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,这与前一个输出相匹配:

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

stats_after_insert触发器在INSERT查询之后运行,并用集合的当前数据(countvalue)更新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_updatestats_after_delete。当你在collectibles表上执行UPDATEDELETE语句时,这两个触发器都会在collectible_stats表上运行。

成功创建这些触发器后,将打印以下输出:

OutputQuery OK, 0 row affected (0.009 sec)

现在,更新其中一件收藏品的价格:

UPDATE collectibles SET value = 25.00 WHERE name = 'AIRCRAFT MODEL';

WHERE子句过滤要更新的行,SET子句将值更改为25.00

输出确认了该语句只修改了一行:

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

同样,在更新后检查汇总表的内容:

SELECT * FROM collectibles_stats;

value现在列出了40.00,这是更新后的正确值:

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

最后一步是验证汇总表是否正确地反映了收藏品的删除。尝试用下面的语句删除飞机模型:

DELETE FROM collectibles WHERE name = 'AIRCRAFT MODEL';
OutputQuery OK, 1 row affected (0.004 sec)

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

SELECT * FROM collectibles;
Output+-----------------+-------+
| name            | value |
+-----------------+-------+
| SPACESHIP MODEL | 15.00 |
+-----------------+-------+
1 row in set (0.000 sec)

现在只剩下SPACESHIP MODEL了。接下来,检查汇总表中的值:

SELECT * FROM collectibles_stats;
Output+-------+-------+
| count | value |
+-------+-------+
|     1 | 15.00 |
+-------+-------+
1 row in set (0.000 sec)

count列现在显示在主表中只有一个可收集的元素。总值为15.00,与SPACESHIP MODEL的值匹配。

这三个触发器在INSERTUPDATEDELETE查询之后共同工作,以保持汇总表与完整的收藏品列表同步。

在下一节中,您将学习如何处理现有的数据库触发器。

列出和删除触发器

在前面几节中,我们创建了新的触发器。因为触发器是在数据库中定义的命名对象,就像表一样,你也可以列出它们并在需要时操作它们。

列出所有触发器、执行SHOW TRIGGERSSQL语句:

SHOW TRIGGERS;

输出将包括所有触发器,包括它们的名称、触发事件的时间(BEFOREAFTER语句执行),以及作为触发器主体的语句和触发器定义的其他详细信息:

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)

To delete existing triggers, you can use DROP TRIGGER SQL statements. Perhaps you no longer want to enforce uppercase letters for collectible names, so the uppercase_before_insert and uppercase_before_update are no longer needed. Execute the following commands to remove these two triggers:
删除现有的触发器,可以使用DROP TRIGGER SQL语句。也许你不再想执行收藏的大写字母的名字,所以“uppercase_before_insert”和“uppercase_before_update”不再需要。执行以下命令删除这两个触发器:

DROP TRIGGER uppercase_before_insert;
DROP TRIGGER uppercase_before_update;
OutputQuery OK, 0 rows affected (0.004 sec)

现在,有了这两个触发器,让我们添加一个新的小写收藏品:

INSERT INTO collectibles VALUES ('ship model', 10.00);
OutputQuery OK, 1 row affected (0.009 sec)

你可以通过执行SELECT查询来验证该行是否被插入:

SELECT * FROM collectibles;
Output+-----------------+-------+
| name            | value |
+-----------------+-------+
| SPACESHIP MODEL | 15.00 |
| ship model      | 10.00 |
+-----------------+-------+
2 rows in set (0.000 sec)

新添加的收藏品是小写字母。由于名称与原始输出相比没有改变,您已经确认以前转换字母大小写的触发器不再使用。

现在你知道了如何按名称列出和删除触发器。

总结

通过本指南,你了解了什么是SQL触发器,以及如何在MySQL中使用它们在INSERTUPDATE查询之前操作数据。你学习了如何使用BEFORE DELETE触发器将删除的行归档到单独的表中,以及如何使用AFTER语句触发器来保持汇总始终是最新的。

你可以使用函数将一些数据操作和验证交给数据库引擎,以确保数据完整性或对日常数据库用户隐藏一些数据库行为。本教程只介绍了为此目的使用触发器的基础知识。你可以构建由多个语句组成的复杂触发器,并使用条件逻辑更细粒度地执行操作。要了解更多信息,请参阅MySQL关于触发器的文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/76250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【微服务】五. Nacos服务注册

Nacos服务注册 5.1 Nacos服务分级存储模型Nacos服务分级存储模型:服务集群属性:总结: 5.2 根据集群负载均衡总结 5.3 Nacos服务实例的权重设置总结: 5.6 环境隔离namespace总结 5.7 Nacos和Eureka的对比总结 5.1 Nacos服务分级存储…

C#数据类型:object、var和dynamic的比较与应用

文章目录 引言:一、object类型:object类型的使用场景:object类型的限制: 二、var类型:var类型的使用场景:var类型的限制: 三、dynamic类型:dynamic类型的使用场景:dynami…

buildroot中C语言使用libconfig的实例

首先在buildroot中开启libconfig 在config中添加 BR2_PACKAGE_LIBCONFIGy 下面是官方给出来的3个实例 /* ----------------------------------------------------------------------------libconfig - A library for processing structured configuration filesCopyright (…

科技云报道:AI时代,对构建云安全提出了哪些新要求?

科技云报道原创。 随着企业上云的提速,一系列云安全问题也逐渐暴露出来,云安全问题得到重视,市场不断扩大。 Gartner 发布“2022 年中国 ICT 技术成熟度曲线”显示,云安全已处于技术萌芽期高点,预期在2-5年内有望达到…

Material Design系列探究之LinearLayoutCompat

谷歌Material Design推出了许多非常好用的控件,所以我决定写一个专题来讲述MaterialDesign,今天带来Material Design系列的第一弹 LinearLayoutCompat。 以前要在LinearLayout布局之间的子View之间添加分割线,还需要自己去自定义控件进行添加…

自动驾驶多任务框架Hybridnets——同时处理车辆检测、可驾驶区域分割、车道线分割模型部署(C++/Python)

一、多感知任务 在移动机器人的感知系统,包括自动驾驶汽车和无人机,会使用多种传感器来获取关键信息,从而实现对环境的感知和物体检测。这些传感器包括相机、激光雷达、雷达、惯性测量单元(IMU)、全球导航卫星系统&am…

Spark 增量抽取 Mysql To Hive

题目要求: 抽取ds_db01库中customer_inf的增量数据进入Hive的ods库中表customer_inf。根据ods.user_info表中modified_time作为增量字段,只将新增的数据抽入,字段名称、类型不变,同时添加静态分区,分区字段为etl_date&…

SpringCloud(二)

1.Nacos配置管理 Nacos除了可以做注册中心,同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案&#…

NIFI实现数据库数据增量同步

说明 nifi版本:1.23.2(docker镜像) 需求背景 将数据库中的数据同步到另一个数据库中,要求对于新增的数据和历史有修改的数据进行增量同步 模拟数据 建表语句 源数据库和目标数据库结构要保持一致,这样可以避免后…

固定资产管理数据怎么算?

在企业的运营中,固定资产的管理是一个至关重要的环节。然而,对于许多企业来说,理解和管理这些资产的数据却常常是一团迷雾。那么,固定资产管理数据究竟应该如何计算呢?这是一个需要我们深入探讨的问题。  我们需要明…

MySQL——命令行客户端的字符集问题

原因:服务器端认为你的客户端的字符集是utf-8,而实际上你的客户端的字符集是GBK。 查看所有字符集:SHOW VARIABLES LIKE character_set_%; 解决方案,设置当前连接的客户端字符集 “SET NAMES GBK;”

Android12之/proc/pid/status参数含义(一百六十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

python sorted函数详解2023.9.11

sorted函数详解 1. 输入和输出2. key传入函数 1. 输入和输出 help(sorted) Help on built-in function sorted in module builtins: sorted(iterable, /, *, keyNone, reverseFalse)Return a new list containing all items from the iterable in ascending order.A custom k…

Redis监控工具_RedisLive

Redis监控工具_RedisLive Redis安装请看: MacBook安装Redis redis集群搭建_亲自操作 RedisLive安装 RedisLive是由python编写的并且开源的图形化监控工具,非常轻量级,核心服务部分只包含一个web服务和一个基于redis自带的info命令以及monitor命令的…

php://filter协议在任意文件读取漏洞(附例题)

php://filter php://fiter 中文叫 元器封装,咱也不知道为什么这么翻译,目前我的理解是可以通过这个玩意对上面提到的php IO流进行处理,及现在可以对php的 IO流进行一定操作。 过滤器:及通过php://filter 对php 的IO流进行的具体…

微服务之流控、容错组件sentinel

背景 2012年阿里巴巴研发的流量治理组件,核心功能流控、容错 有什么功能 流量控制 流量控制 网关控制 黑白名单 熔断降级 熔断 保护分布式系统防止因为调用下有服务时产生故障或者请求超时等异常影响上游服务,使用熔断方案,类似断路器…

hive中的索引

使用索引前的配置 在使用Hive索引之前,需要进行一些配置,以确保索引能够正常工作。以下是一些常见的配置步骤: Hive配置 在Hive中启用索引功能,需要在Hive配置文件(hive-site.xml)中设置以下属性&#x…

T2I-Adapter:增强文本到图像生成的控制能力

链接:GitHub - TencentARC/T2I-Adapter: T2I-Adapter 文本到图像生成 (T2I) 是人工智能领域的一个重要研究方向。近年来,随着深度学习技术的发展,T2I 技术取得了显著进展,生成的图像在视觉效果上已经与真实图像难以区分。 然而&…

ILS解析漏洞复现

搭建好ILS后,访问127.0.0.1:8000 写一个phpinfo的脚本 可以看到。现在是不能访问的 赋予 IIS 解析 phpinfo 能力 打开服务器管理器,打开 IIS 管理器 点击处理程序映射 再次访问,发现程序可以访问 将index.php改为index.png 此时php脚本自然是…

【pdf密码】如何限制他人对PDF文件编辑?

制作好的PDF文件,先要设置一个密码防止他人对文件进行编辑,那么我们可以对PDF文件设置限制编辑,设置方法很简单,我们在PDF编辑器中点击文件 – 属性 – 安全,在权限下拉框中选中【密码保护】 然后在密码保护界面中&…