SQLShack

Los SQL Triggers son otro poderoso objeto de base de datos que tenemos a nuestra disposición. En artículos anteriores, hemos cubierto las funciones definidas por el usuario, los procedimientos definidos por el usuario y las Vistas SQL. Hoy hablaremos de los triggers SQL y de cómo utilizarlos para conseguir el comportamiento deseado.

El modelo

Antes de pasar al tema de este artículo, echemos un vistazo rápido al modelo que estamos utilizando en este artículo pero también a lo largo de esta serie.

Disparadores SQL - el modelo de datos que utilizaremos en el artículo'll use in the article

En este artículo, nos centraremos en los disparadores DML (lenguaje de manipulación de datos) y mostraremos cómo funcionan cuando realizamos cambios en una única tabla.

¿Qué son los disparadores SQL?

En SQL Server, los triggers son objetos de la base de datos, en realidad, un tipo especial de procedimiento almacenado, que «reacciona» a ciertas acciones que realizamos en la base de datos. La idea principal de los triggers es que siempre realizan una acción en caso de que ocurra algún evento. Si hablamos de triggers DML, estos cambios serán cambios en nuestros datos. Examinemos algunas situaciones interesantes:

  • En caso de que realices una inserción en la tabla de llamadas, quieres actualizar que el cliente relacionado tiene 1 llamada más (en ese caso, deberíamos tener el atributo integer en la tabla de clientes)
  • Cuando completes una llamada (actualizar llamada.valor del atributo end_time) se quiere aumentar el contador de llamadas realizadas por ese empleado durante ese día (de nuevo, deberíamos tener dicho atributo en la tabla de empleados)
  • Cuando se intenta eliminar un empleado, se quiere comprobar si tiene llamadas relacionadas. Si es así, impedirá ese borrado y lanzará una excepción personalizada
  • De los ejemplos, se puede observar que los triggers DML son acciones relacionadas con los comandos SQL definidos en estos triggers. Dado que son similares a los procedimientos almacenados, puede probar valores utilizando la sentencia IF, etc. Esto proporciona una gran flexibilidad.

    La buena razón para utilizar los triggers DML SQL es el caso en el que se quiere asegurar que un determinado control se realizará antes o después de la sentencia definida en la tabla definida. Este podría ser el caso cuando su código está por todas partes, por ejemplo, la base de datos es utilizada por diferentes aplicaciones, el código está escrito directamente en las aplicaciones y no lo tiene bien documentado.

    Tipos de SQL Triggers

    En SQL Server, tenemos 3 grupos de triggers:

    • DML (lenguaje de manipulación de datos) triggers – Ya los hemos mencionado, y reaccionan a los comandos DML. Estos son – INSERT, UPDATE y DELETE
    • Triggers DDL (lenguaje de definición de datos) – Como era de esperar, los triggers de este tipo reaccionarán a los comandos DDL como – CREATE, ALTER y DROP
    • Triggers de inicio de sesión – El nombre lo dice todo. Este tipo reacciona a los eventos LOGON
      • En este artículo, nos centraremos en los triggers DML, porque son los más utilizados. Cubriremos los dos tipos de trigger restantes en los próximos artículos de esta serie.

        Triggers DML – Sintaxis

        La sintaxis SQL simplificada para definir el trigger es la siguiente.

        1
        2
        3

        .

        4
        5

        CREATE TRIGGER trigger_name
        ON table_name
        {FOR | AFTER | INSTEAD OF} { }
        Como
        {sql_statements}

        La mayor parte de la sintaxis debería explicarse por sí misma. La idea principal es definir:

        • Un conjunto de {sql_statements} que se ejecutarán cuando se dispare el trigger (definido por los parámetros restantes)
        • Debemos definir cuándo se dispara el trigger. Eso es lo que hace la parte {FOR | AFTER | INSTEAD OF}. Si nuestro trigger se define como FOR | AFTER | INSTEAD OF trigger entonces las sentencias SQL del trigger se ejecutarán después de que todas las acciones que dispararon este trigger se lancen con éxito. El trigger INSTEAD OF realizará controles y sustituirá la acción original por la acción del trigger, mientras que el trigger FOR | AFTER (significan lo mismo) ejecutará comandos adicionales después de que la sentencia original haya finalizado
        • La parte { } denota qué comando dispara realmente este trigger. Debemos especificar al menos una opción, pero podríamos usar varias si lo necesitamos
          • Con esto en mente, podemos escribir fácilmente disparadores que:

            • Comprobar (antes de la inserción) si todos los parámetros de la sentencia INSERT están bien, añadir algunos si es necesario, y realizar la inserción
            • Después de la inserción, realizar tareas adicionales, como actualizar un valor en otra tabla
            • Antes de la eliminación, comprobar si hay registros relacionados
            • Actualizar ciertos valores (e.g. archivo de registro) después de la eliminación se hace
              • Si desea soltar un disparador, que va a utilizar:

                1
                DROP TRIGGER trigger_name;

                Disparador SQL INSERT – Ejemplo

                En primer lugar, crearemos un sencillo disparador SQL que realizará la comprobación antes de la sentencia INSERT.

                1
                2
                3
                5

                .

                6
                7
                8
                9
                10
                11

                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 @nombre_país_es CHAR(128);
                DECLARE @country_code CHAR(8);
                SELECT @nombre_de_país = nombre_de_país, @nombre_de_país = nombre_de_país, @código_de_país = código_de_país FROM INSERTED;
                IF @nombre_de_país ES NULL SET @nombre_de_país = @nombre_de_país;
                IF @nombre_de_país ES NULL SET @nombre_de_país = @nombre_de_país;
                INSERT INTO país (nombre_país, nombre_país_es, código_país) VALUES (@nombre_país, @nombre_país_es, @código_país);
                END;

                Podemos ver nuestro trigger en el Explorador de Objetos, cuando expandimos los datos de la tabla relacionada (país).

                explorador de objetos

                explorador de objetos

                Quiero destacar algunas cosas aquí:

                • La sentencia INSERT dispara esta consulta y en realidad se sustituye (INSTEAD OF INSERT) por la sentencia de este trigger
                • Hemos definido una serie de variables locales para almacenar los valores del registro de inserción original (INSERTED). Este registro es específico para los triggers y permite acceder a este único registro y a sus valores
                    • Nota: El registro INSERTED puede utilizarse en los triggers SQL de inserción y actualización.
                      • Con las sentencias IF, hemos comprobado los valores y SET los valores si no estaban establecidos antes
                      • Al final de la consulta, realizamos la sentencia INSERT (la que sustituye a la original que disparó este trigger)
                        • Ejecutamos ahora un comando INSERT INTO y vemos qué ocurre en la base de datos. Ejecutaremos las siguientes sentencias:

                          1
                          2
                          3

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

                          El resultado está en la imagen de abajo.

                          el resultado de la sentencia de inserción

                          el resultado de la sentencia de inserción

                          Puedes notar fácilmente que la fila con id = 10, había sido insertada. No hemos especificado el nombre_de_país, pero el trigger ha hecho su trabajo y ha rellenado ese valor con nombre_de_país.

                          • Nota: Si el trigger está definido en una determinada tabla, para una determinada acción, se ejecutará siempre cuando se realice esta acción.

                          Disparador SQL DELETE – Ejemplo

                          Ahora vamos a crear un disparador que se disparará ante la sentencia DELETE en la tabla país.

                          1
                          2
                          3
                          4
                          5

                          .

                          6
                          7
                          8
                          9
                          10
                          11
                          13

                          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;

                          Para este trigger, cabe destacar lo siguiente:

                          • Una vez más, realizamos la acción antes (en lugar de) de ejecutar realmente (INSTEAD OF DELETE)
                          • Hemos utilizado el registro DELETED. Este registro se puede utilizar en los triggers relacionados con la sentencia DELETE
                          • Nota: El registro DELETED se puede utilizar en los triggers SQL de borrado y actualización.
                            • Hemos utilizado la sentencia IF para determinar si la fila debe o no debe ser borrada. Si debe, hemos realizado la sentencia DELETE, y si no debe, se nos lanza una excepción
                              • La ejecución de la siguiente sentencia ha ido sin error porque el país con id = 6 no tenía registros relacionados.

                                1
                                DELETE FROM country WHERE id = 6;

                                Si ejecutamos esta sentencia veremos un mensaje de error personalizado, como se muestra en la siguiente imagen.

                                1
                                DELETE FROM country WHERE id = 1;

                                el mensaje de error lanzado por el SQL trigger

                                el mensaje de error lanzado por el trigger SQL

                                Este mensaje no sólo es descriptivo, sino que nos permite tratar este error de forma agradable y mostrar un mensaje más significativo al usuario final.

                                Disparador SQL UPDATE

                                Este lo dejaré para ti, como práctica. Así que intenta escribir el trigger UPDATE. Lo importante que debes saber es que en el trigger de actualización puedes usar ambos – registros INSERTADOS (después de la actualización) y BORRADOS (antes de la actualización). En casi todos los casos, necesitarás utilizar ambos.

                                ¿Cuándo utilizar los disparadores SQL?

                                Los disparadores tienen mucho en común con los procedimientos almacenados. Sin embargo, en comparación con los procedimientos almacenados son limitados en lo que puede hacer. Por lo tanto, prefiero tener un procedimiento almacenado para insertar/actualizar/borrar y hacer todas las comprobaciones y acciones adicionales allí.

                                Aún así, esa no es siempre la opción. Si has heredado un sistema o simplemente no quieres poner toda la lógica en los procedimientos almacenados, entonces los triggers podrían ser una solución para muchos problemas que puedas tener.

                                Tabla de contenidos

                                Aprende SQL: CREATE DATABASE & CREATE TABLE Operations

                                Aprende SQL: INSERT INTO TABLE

                                Aprender SQL: Clave primaria

                                Aprende SQL: Clave foránea

                                Aprender SQL: Sentencia SELECT

                                Aprende SQL: INNER JOIN vs LEFT JOIN

                                Aprende SQL: Scripts SQL

                                Aprende SQL: Tipos de relaciones

                                Aprender SQL: Unir varias tablas

                                Aprender SQL: Funciones agregadas

                                Aprender SQL: ¿Cómo escribir una consulta SELECT compleja?

                                Aprende SQL: La base de datos INFORMATION_SCHEMA

                                Aprende SQL: Tipos de Datos SQL

                                Aprende SQL: Teoría de conjuntos

                                Aprender SQL: Funciones definidas por el usuario

                                Aprender SQL: Procedimientos almacenados definidos por el usuario

                                Aprender SQL: Vistas SQL

                                Aprender SQL: SQL Triggers

                                Aprender SQL: Practicar consultas SQL

                                Aprender SQL: Ejemplos de consultas SQL

                                Aprender SQL: Crear un informe manualmente utilizando consultas SQL

                                Aprender SQL: Funciones de fecha y hora de SQL Server

                                Aprender SQL: Crear informes de SQL Server utilizando funciones de fecha y hora

                                Aprender SQL: Tablas dinámicas de SQL Server

                                Aprender SQL: Exportación de SQL Server a Excel

                                Aprender SQL: Introducción a los bucles de SQL Server

                                Aprender SQL: Cursores de SQL Server

                                Aprender SQL: SQL Best Practices for Deleting and Updating data

                                Aprender SQL: Convenciones de nomenclatura

                                Aprender SQL: Trabajos relacionados con SQL

                                Aprende SQL: Uniones no equis en SQL Server

                                Aprender SQL: Inyección SQL

                                Aprender SQL: SQL dinámico

                                • Autor
                                • Postes recientes
                                Emil Drkusic
                                Emil es un profesional de las bases de datos con más de 10 años de experiencia en todo lo relacionado con ellas. Durante estos años, ha trabajado en la industria de la informática y las finanzas y ahora trabaja como freelance.
                                Sus compromisos pasados y presentes varían desde el diseño y la codificación de bases de datos hasta la enseñanza, la consultoría y la escritura sobre bases de datos. Tampoco hay que olvidar, el BI, la creación de algoritmos, el ajedrez, la filatelia, 2 perros, 2 gatos, 1 esposa, 1 bebé…
                                Puedes encontrarlo en LinkedIn
                                Ver todos los posts de Emil Drkusic
                                Emil Drkusic
                                Últimos posts de Emil Drkusic (ver todos)
                                • Aprende SQL: SQL dinámico – 3 de marzo de 2021
                                • Aprender SQL: Inyección SQL – 2 de noviembre de 2020
                                • Aprende SQL: Non-Equi Joins en SQL Server – 29 de septiembre de 2020

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *