sql 触发器未触发_学习SQL:SQL触发器

sql 触发器未触发

SQL Triggers are another powerful database object we have at our disposal. In previous articles, we’ve covered user-defined functions, user-defined procedures, and SQL Views. Today we’ll talk about SQL triggers and how to use them to achieve the desired behavior.

SQL触发器是我们可以使用的另一个强大的数据库对象。 在先前的文章中,我们介绍了用户定义的函数 , 用户定义的过程和SQL视图 。 今天,我们将讨论SQL触发器以及如何使用它们来实现所需的行为。

该模型 (The Model)

Before we move to the topic of this article, let’s take a quick look at the model we’re using in this article but also throughout this series.

在转到本文主题之前,让我们快速看一下本文中以及本系列中使用的模型。

sql 触发器未触发_学习SQL:SQL触发器_第1张图片

In this article, we’ll focus on DML (data manipulation language) triggers and show how they function when we make changes in a single table.

在本文中,我们将重点介绍DML(数据操作语言)触发器,并说明在单个表中进行更改时它们如何工作。

什么是SQL触发器?
(What Are SQL Triggers?
)

In SQL Server, triggers are database objects, actually, a special kind of stored procedure, which “reacts” to certain actions we make in the database. The main idea behind triggers is that they always perform an action in case some event happens. If we’re talking about DML triggers, these changes shall be changes in our data. Let’s examine a few interesting situations:

在SQL Server中,触发器是数据库对象,实际上是一种特殊的存储过程,它对我们在数据库中执行的某些操作“做出React”。 触发器背后的主要思想是,万一发生某些事件,它们总是执行一个动作。 如果我们在谈论DML触发器,则这些更改将是我们数据中的更改。 让我们研究一些有趣的情况:

  • call table, you want to update that related customer has 1 more call (in that case, we should have integer attribute in the 调用表中执行插入操作,则要更新相关客户还有1个调用(在这种情况下,我们在customer table) 客户表中应具有integer属性)
  • call (update call.end_time attribute value) you want to increase the counter of calls performed by that employee during that day (again, we should have such attribute in the 通话后 (更新call.end_time属性值),您希望增加该员工当天的通话次数(同样, employee table) employee表中应具有该属性)
  • employee, you want to check if it has related calls. If so, you’ll prevent that delete and raise a custom exception 员工时 ,您要检查它是否有相关呼叫。 如果是这样,您将阻止该删除并引发自定义异常

From examples, you can notice that DML triggers are actions related to the SQL commands defined in these triggers. Since they are similar to stored procedures, you can test values using the IF statement, etc. This provides a lot of flexibility.

从示例中,您可以注意到DML触发器是与这些触发器中定义SQL命令相关的操作。 由于它们类似于存储过程,因此可以使用IF语句等测试值。这提供了很大的灵活性。

The good reason to use DML SQL triggers is the case when you want to assure that a certain control shall be performed before or after the defined statement on the defined table. This could be the case when your code is all over the place, e.g. database is used by different applications, code is written directly in applications and you don’t have it well-documented.

使用DML SQL触发器的充分理由是,当您要确保在定义的表上的定义的语句之前或之后执行某些控件时。 当您的代码无处不在时,可能是这种情况,例如,数据库被不同的应用程序使用,代码直接编写在应用程序中,而您没有充分的文档说明。

SQL触发器的类型 (Types of SQL Triggers)

In SQL Server, we have 3 groups of triggers:

在SQL Server中,我们有3组触发器:

  • DML (data manipulation language) triggers – We’ve already mentioned them, and they react to DML commands. These are – INSERT, UPDATE, and DELETE

    DML(数据操作语言)触发器–我们已经提到过它们,它们对DML命令做出React。 它们是– INSERT,UPDATE和DELETE
  • DDL (data definition language) triggers – As expected, triggers of this type shall react to DDL commands like – CREATE, ALTER, and DROP

    DDL(数据定义语言)触发器–如预期的那样,此类型的触发器应对DDL命令做出响应,例如CREATE,ALTER和DROP
  • Logon triggers – The name says it all. This type reacts to LOGON events

    登录触发器–名称说明了一切。 此类型对LOGON事件作出React

In this article, we’ll focus on DML triggers, because they are most commonly used. We’ll cover the remaining two trigger types in the upcoming articles of this series.

在本文中,我们将重点介绍DML触发器,因为它们是最常用的。 在本系列的后续文章中,我们将介绍其余两种触发器类型。

DML触发器–语法 (DML Triggers – Syntax)

The simplified SQL syntax to define the trigger is as follows.

定义触发器的简化SQL语法如下。

CREATE TRIGGER [schema_name.]trigger_name
ON table_name
{FOR | AFTER | INSTEAD OF} {[INSERT] [,] [UPDATE] [,] [DELETE]}
AS
{sql_statements}

Most of the syntax should be self-explanatory. The main idea is to define:

大多数语法应该是不言自明的。 主要思想是定义:

  • A set of {sql_statements} that shall be performed when the trigger is fired (defined by remaining parameters)
  • 触发触发器时应执行的一组{sql_statements} (由其余参数定义)
  • We must define when the trigger is fired. That is what the part {FOR | AFTER | INSTEAD OF} does. If our trigger is defined as FOR | AFTER | INSTEAD OF trigger than SQL statements in the trigger shall run after all actions that fired this trigger is launched successfully. The INSTEAD OF trigger shall perform controls and replace the original action with the action in the trigger, while the FOR | AFTER (they mean the same) trigger shall run additional commands after the original statement has completed
  • 我们必须定义触发触发器的时间。 这就是{FOR | 之后| INSTEAD OF}可以。 如果我们的触发器定义为FOR | 之后| INSTEAD OF触发器比触发器中SQL语句应在成功触发该触发器的所有操作启动后运行。 INSTEAD OF触发器应执行控制并将原始操作替换为触发器中的操作,而FOR | 原始语句完成后, AFTER (它们的意思相同)触发器应运行其他命令
  • The part {[INSERT] [,] [UPDATE] [,] [DELETE]} denotes which command actually fires this trigger. We must specify at least one option, but we could use multiple if we need it

    {[INSERT] [,] [UPDATE] [,] [DELETE]}部分表示实际触发该触发器的命令。 我们必须至少指定一个选项,但是如果需要,可以使用多个

With this in mind, we can easily write triggers that will:

考虑到这一点,我们可以轻松地编写触发器,该触发器将:

  • Check (before insert) if all parameters of the INSERT statement are OK, add some if needed, and perform the insert

    (在插入之前)检查INSERT语句的所有参数是否都正确,如果需要,添加一些参数,然后执行插入
  • After insert, perform additional tasks, like updating a value in another table

    插入后,执行其他任务,例如更新另一个表中的值
  • Before delete, check if there are related records

    删除前,请检查是否有相关记录
  • Update certain values (e.g. log file) after the delete is done

    删除完成后更新某些值(例如日志文件)

If you want to drop a trigger, you’ll use:

如果要删除触发器,请使用:

DROP TRIGGER [schema_name.]trigger_name;

SQL INSERT触发器–示例 (SQL INSERT Trigger – Example)

First, we’ll create a simple SQL trigger that shall perform check before the INSERT statement.

首先,我们将创建一个简单SQL触发器,该触发器将在INSERT语句之前执行检查。

DROP TRIGGER IF EXISTS t_country_insert;
GO
CREATE TRIGGER t_country_insert ON country INSTEAD OF INSERT
AS BEGIN
    DECLARE @country_name CHAR(128);
    DECLARE @country_name_eng CHAR(128);
    DECLARE @country_code  CHAR(8);
    SELECT @country_name = country_name, @country_name_eng = country_name_eng, @country_code = country_code FROM INSERTED;
    IF @country_name IS NULL SET @country_name = @country_name_eng;
    IF @country_name_eng IS NULL SET @country_name_eng = @country_name;
    INSERT INTO country (country_name, country_name_eng, country_code) VALUES (@country_name, @country_name_eng, @country_code);
END;

We can see our trigger in the Object Explorer, when we expand the data for the related table (country).

展开相关表( 国家/地区 )的数据时,我们可以在对象资源管理器中看到触发器。

sql 触发器未触发_学习SQL:SQL触发器_第2张图片

I want to emphasize a few things here:

我想在这里强调一些事情:

  • The INSERT statement fires this query and is actually replaced (INSTEAD OF INSERT) with the statement in this trigger

    INSERT语句触发该查询,并实际上被此触发器中的语句替换(INSTEAD OF INSERT)
  • We’ve defined a number of local variables to store values from the original insert record (INSERTED). This record is specific for triggers and it allows you to access this single record and its’ values

    我们定义了许多局部变量来存储原始插入记录(INSERTED)中的值。 该记录是特定于触发器的,它允许您访问该单个记录及其值
  • Note: The INSERTED record can be used in the insert and update SQL triggers.注意:可以在插入和更新SQL触发器中使用INSERTED记录。
  • With IF statements, we’ve tested values and SET values if they were not set before

    使用IF语句,我们已经测试了值和SET值(如果之前未设置)
  • At the end of the query, we performed the INSERT statement (the one replacing the original one that fired this trigger)

    在查询结束时,我们执行了INSERT语句(该语句替换了触发该触发器的原始语句)

Let’s now run an INSERT INTO command and see what happens in the database. We’ll run the following statements:

现在让我们运行INSERT INTO命令,看看数据库中发生了什么。 我们将运行以下语句:

SELECT * FROM country;
INSERT INTO country (country_name_eng, country_code) VALUES ('United Kingdom', 'UK');
SELECT * FROM country;

The result is in the picture below.

结果如下图所示。

sql 触发器未触发_学习SQL:SQL触发器_第3张图片

You can easily notice that the row with id = 10, had been inserted. We haven’t specified the country_name, but the trigger did its’ job and filled that value with country_name_eng.

您可以轻松地注意到,已插入id = 10的行。 我们没有指定country_name,但是触发器完成了工作,并用country_name_eng填充了该值。

  • Note: If the trigger is defined on a certain table, for a certain action, it shall always run when this action is performed.注意:如果触发器是在某个表上定义的,则对于某个动作,它应在执行该动作时始终运行。

SQL DELETE触发器–示例 (SQL DELETE Trigger – Example)

Now let’s create a trigger that shall fire upon the DELETE statement on the country table.

现在,让我们创建一个触发器,该触发器将在country表上的DELETE语句上触发。

DROP TRIGGER IF EXISTS t_country_delete;
GO
CREATE TRIGGER t_country_delete ON country INSTEAD OF DELETE
AS BEGIN
    DECLARE @id INT;
    DECLARE @count INT;
    SELECT @id = id FROM DELETED;
    SELECT @count = COUNT(*) FROM city WHERE country_id = @id;
    IF @count = 0
        DELETE FROM country WHERE id = @id;
    ELSE
        THROW 51000, 'can not delete - country is referenced in other tables', 1;
END;

For this trigger, it’s worth to emphasize the following:

对于此触发器,值得强调以下几点:

  • Once again, we perform the action before (instead of) actual executing (INSTEAD OF DELETE)

    再一次,我们在(而不是)实际执行(INSTEAD OF DELETE)之前执行动作
  • We’ve used record DELETED. This record can be used in the triggers related to the DELETE statement

    我们使用了记录DELETED。 该记录可用于与DELETE语句相关的触发器
  • Note: The DELETED record can be used in delete and update SQL triggers.注意: DELETED记录可用于删除和更新SQL触发器。
  • We’ve used the IF statement to determine if the row should or shouldn’t be deleted. If it should, we’ve performed the DELETE statement, and if shouldn’t, we’re thrown and exception

    我们使用IF语句来确定是否应该删除该行。 如果应该,则执行了DELETE语句,如果不应该,则抛出了异常

Running the below statement went without an error because the country with id = 6 had no related records.

运行下面的语句没有错误,因为id = 6的国家没有相关记录。

DELETE FROM country WHERE id = 6;

If we run this statement we’ll see a custom error message, as shown in the picture below.

如果运行此语句,我们将看到一个自定义错误消息,如下图所示。

DELETE FROM country WHERE id = 1;

sql 触发器未触发_学习SQL:SQL触发器_第4张图片

Such a message is not only descriptive, but allows us to treat this error nicely and show a more meaningful message to the end-user.

这样的消息不仅具有描述性,还使我们能够很好地处理此错误,并向最终用户显示更有意义的消息。

SQL UPDATE触发器 (SQL UPDATE Trigger)

I will leave this one to you, as a practice. So try to write down the UPDATE trigger. The important thing you should know is that in the update trigger you can use both – INSERTED (after update) and DELETED (before update) records. In almost all cases, you’ll need to use both of them.

作为练习,我将把这个留给您。 因此,请尝试写下UPDATE触发器。 您应该知道的重要一点是,在更新触发器中,可以同时使用– INSERTED(更新后)和DELETED(更新前)记录。 在几乎所有情况下,都需要同时使用它们。

何时使用SQL触发器? (When to Use SQL Triggers?)

Triggers share a lot in common with stored procedures. Still, compared to stored procedures they are limited in what you can do. Therefore, I prefer to have one stored procedure for insert/update/delete and make all checks and additional actions there.

触发器与存储过程有很多共同点。 但是,与存储过程相比,它们在执行操作方面受到限制。 因此,我更喜欢使用一个存储过程来进行插入/更新/删除,并在那里进行所有检查和其他操作。

Still, that is not always the option. If you inherited a system or you simply don’t want to put all the logic in the stored procedures, then triggers could a solution for many problems you might have.

尽管如此,这并不总是选择。 如果您继承了一个系统,或者只是不想将所有逻辑都放在存储过程中,那么触发器可以解决您可能遇到的许多问题。

目录 (Table of contents)

Learn SQL: CREATE DATABASE & CREATE TABLE Operations
Learn SQL: INSERT INTO TABLE
Learn SQL: Primary Key
Learn SQL: Foreign Key
Learn SQL: SELECT statement
Learn SQL: INNER JOIN vs LEFT JOIN
Learn SQL: SQL Scripts
Learn SQL: Types of relations
Learn SQL: Join multiple tables
Learn SQL: Aggregate Functions
Learn SQL: How to Write a Complex SELECT Query?
Learn SQL: The INFORMATION_SCHEMA Database
Learn SQL: SQL Data Types
Learn SQL: Set Theory
Learn SQL: User-Defined Functions
Learn SQL: User-Defined Stored Procedures
Learn SQL: SQL Views
Learn SQL: SQL Triggers
Learn SQL: Practice SQL Queries
Learn SQL: SQL Query examples
Learn SQL: Create a report manually using SQL queries
Learn SQL: SQL Server date and time functions
Learn SQL: Create SQL Server reports using date and time functions
Learn SQL: SQL Server Pivot Tables
Learn SQL: SQL Server export to Excel
Learn SQL: Intro to SQL Server loops
Learn SQL: SQL Server Cursors
Learn SQL: SQL Best Practices for Deleting and Updating data
Learn SQL: Naming Conventions
学习SQL:CREATE DATABASE&CREATE TABLE操作
学习SQL:插入表
学习SQL:主键
学习SQL:外键
学习SQL:SELECT语句
学习SQL:INNER JOIN与LEFT JOIN
学习SQL:SQL脚本
学习SQL:关系类型
学习SQL:联接多个表
学习SQL:聚合函数
学习SQL:如何编写复杂的SELECT查询?
学习SQL:INFORMATION_SCHEMA数据库
学习SQL:SQL数据类型
学习SQL:集合论
学习SQL:用户定义的函数
学习SQL:用户定义的存储过程
学习SQL:SQL视图
学习SQL:SQL触发器
学习SQL:练习SQL查询
学习SQL:SQL查询示例
学习SQL:使用SQL查询手动创建报告
学习SQL:SQL Server日期和时间函数
学习SQL:使用日期和时间函数创建SQL Server报表
学习SQL:SQL Server数据透视表
学习SQL:将SQL Server导出到Excel
学习SQL:SQL Server循环简介
学习SQL:SQL Server游标
学习SQL:删除和更新数据SQL最佳实践
学习SQL:命名约定

翻译自: https://www.sqlshack.com/learn-sql-sql-triggers/

sql 触发器未触发

你可能感兴趣的:(触发器,数据库,python,mysql,java)