sql >> Base de Datos >  >> RDS >> Mysql

Trabajar con disparadores en una base de datos MySQL:un tutorial

Un gatillo es un comando SQL predefinido que se ejecuta automáticamente cuando ocurren acciones específicas en la base de datos. Se puede disparar antes o después de un INSERT , UPDATE o DELETE evento.

Los disparadores se utilizan principalmente para mantener la lógica del software en el servidor MySQL y tienen varios beneficios:

  • Los disparadores ayudan a mantener las operaciones globales centralizadas en un solo lugar.

  • Reducen el código del lado del cliente y ayudan a minimizar los viajes de ida y vuelta realizados al servidor de la base de datos.

  • Ayudan a que las aplicaciones sean más escalables en diferentes plataformas.

Algunos casos de uso comunes de disparadores incluyen el registro de auditoría, el cálculo previo de los valores de la base de datos (por ejemplo, sumas acumulativas) y la aplicación de reglas de validación e integridad de datos complejas.

En esta guía, aprenderá:

  • Cómo está estructurada la sintaxis de un disparador.

  • Cómo crear disparadores que se ejecuten antes de que ocurran otros eventos de la base de datos.

  • Cómo crear activadores que se ejecuten después de que ocurran otros eventos de la base de datos.

  • Cómo eliminar disparadores.

Antes de comenzar

  1. Si aún no lo ha hecho, cree una cuenta de Linode y una instancia de cómputo. Consulte nuestras guías Introducción a Linode y Creación de una instancia informática.

  2. Siga nuestra guía de configuración y protección de una instancia informática para actualizar su sistema. También puede establecer la zona horaria, configurar su nombre de host, crear una cuenta de usuario limitada y fortalecer el acceso SSH.

  3. Un servidor MySQL y un cliente instalado en el servidor Linode. Las guías de instalación de MySQL están disponibles para diferentes distribuciones en nuestra sección MySQL.

Preparar la base de datos

Para comprender mejor cómo funcionan los disparadores, crearemos una base de datos de muestra y le agregaremos datos de muestra. Más adelante, crearemos diferentes activadores en la base de datos como ejercicio de prueba de concepto.

  1. Primero, inicie sesión en su servidor MySQL:

    mysql -u root -p
    

    Luego, ingrese la contraseña raíz de su servidor MySQL y presione Enter para proceder.

  2. A continuación, verá un indicador de MySQL similar al que se muestra a continuación:

    mysql >
  3. Crear una test_database ejecutando el siguiente comando:

    CREATE DATABASE test_database;
    

    Salida:

    Query OK, 1 row affected (0.02 sec)
  4. Cambiar a la base de datos:

    USE test_database;
    

    Salida:

    Database changed
  5. Una vez seleccionada la base de datos, crearemos algunas tablas que usaremos para demostrar los disparadores. Comenzaremos creando las stores mesa. Esta tabla contendrá información sobre dos tiendas/oficinas de muestra desde donde opera nuestro negocio hipotético:

    CREATE TABLE stores
    (
    store_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    store_name VARCHAR(50)
    ) ENGINE=InnoDB;
    

    Salida:

    Query OK, 0 rows affected (0.07 sec)
  6. A continuación, agregue dos registros a las stores table ejecutando los siguientes comandos:

    INSERT INTO stores (store_name) VALUES ('Philadelphia');
    INSERT INTO stores (store_name) VALUES ('Galloway');
    

    Después de cada comando, obtendrá el siguiente resultado:

    Query OK, 1 row affected (0.08 sec)
    ...
  7. Confirme los registros ejecutando el siguiente comando:

    SELECT * FROM stores;
    

    Salida:

    +----------+--------------+
    | store_id | store_name   |
    +----------+--------------+
    |        1 | Philadelphia |
    |        2 | Galloway     |
    +----------+--------------+
    2 rows in set (0.01 sec)
  8. A continuación, cree los products mesa. La mesa albergará diferentes productos que se ofrecen en la tienda:

    CREATE TABLE products
    (
    product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    product_name VARCHAR(40),
    cost_price DOUBLE,
    retail_price DOUBLE,
    availability VARCHAR(5)
    ) ENGINE=InnoDB;
    

    Salida:

    Query OK, 0 rows affected (0.13 sec)
    • Cada producto se identificará de forma única mediante un product_id .

    • Un product_name campo especificará los nombres de los elementos.

    • El cost_price y retail_price campos determinarán el precio de compra y venta respectivamente.

    • Una availability La columna definirá la disponibilidad del producto en las diferentes tiendas. Si el producto solo está disponible en nuestra tienda local (Filadelfia), lo indicaremos con un LOCAL valor. De lo contrario, usaremos el valor de ALL para indicar un producto que está disponible en ambas tiendas (Philadelphia y Galloway).

  9. Agregar datos de muestra a los products tabla:

    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('WIRELESS MOUSE', '18.23', '30.25','ALL');
    
    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('8 MP CAMERA', '60.40', '85.40','ALL');
    
    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('SMART WATCH', '189.60', '225.30','LOCAL');
    

    Obtendrá el resultado que se muestra a continuación después de cada comando de inserción:

    Query OK, 1 row affected (0.02 sec)
    ...
  10. Confirme si los productos se insertaron ejecutando el siguiente comando:

    SELECT * FROM products;
    

    Salida:

    +------------+----------------+------------+--------------+--------------+
    | product_id | product_name   | cost_price | retail_price | availability |
    +------------+----------------+------------+--------------+--------------+
    |          1 | WIRELESS MOUSE |      18.23 |        30.25 | ALL          |
    |          2 | 8 MP CAMERA    |       60.4 |         85.4 | ALL          |
    |          3 | SMART WATCH    |      189.6 |        225.3 | LOCAL        |
    +------------+----------------+------------+--------------+--------------+
    3 rows in set (0.00 sec)
  11. A continuación, la disponibilidad de los productos se asignará a otra tabla llamada products_to_stores . Esta tabla solo hará referencia al product_id de los products tabla y el store_id de las stores tabla donde está disponible el artículo.

    Crea los products_to_stores tabla ejecutando el siguiente código:

    CREATE TABLE products_to_stores
    (
    ref_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    product_id BIGINT,
    store_id BIGINT
    ) ENGINE=InnoDB;
    

    Salida:

    Query OK, 0 rows affected (0.14 sec)
  12. A continuación, crearemos un archived_products mesa. La tabla contendrá información sobre los productos eliminados para referencia futura:

    CREATE TABLE archived_products
    (
    product_id BIGINT PRIMARY KEY ,
    product_name VARCHAR(40),
    cost_price DOUBLE,
    retail_price DOUBLE,
    availability VARCHAR(5)
    ) ENGINE=InnoDB;
    

    Salida:

    Query OK, 0 rows affected (0.14 sec)
  13. Por último, crearemos un products_price_history tabla para el seguimiento de los diferentes precios de cada producto a lo largo del tiempo:

    CREATE TABLE products_price_history
    (
    product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    price_date DATETIME,
    retail_price DOUBLE
    ) ENGINE=InnoDB;
    

    Salida:

    Query OK, 0 rows affected (0.14 sec)

Una vez que nuestra estructura de base de datos esté en su lugar, ahora podemos continuar y aprender la sintaxis básica de un disparador de base de datos MySQL para crear nuestra primera muestra.

Sintaxis de activación

Como se indicó anteriormente, los activadores se activan automáticamente antes o después de ejecutar un comando SQL en la base de datos. La sintaxis básica para crear disparadores es la siguiente:

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

[TRIGGER BODY];
  • TRIGGER_NAME :Cada activador debe tener un nombre único y debe definirlo aquí.

  • TRIGGER_TIME :Cualquiera BEFORE o AFTER .

  • TRIGGER_EVENT :debe especificar el evento de la base de datos que invocará el disparador:INSERT , UPDATE o DELETE .

  • TRIGGER BODY :Esto especifica el comando SQL real (o los comandos) que desea que su disparador ejecute.

Si el cuerpo de un disparador tiene más de una instrucción SQL, debe encerrarlo dentro de un BEGIN...END cuadra. Además, deberá cambiar temporalmente el DELIMITER que señala el final del cuerpo del disparador a un nuevo valor. Esto asegura que las declaraciones dentro del cuerpo no sean interpretadas prematuramente por su cliente MySQL. Un ejemplo de esto se parece a lo siguiente:

DELIMITER &&

CREATE TRIGGER TRIGGER_NAME

TRIGGER_TIME TRIGGER_EVENT

ON TABLE_NAME FOR EACH ROW

BEGIN

[TRIGGER BODY]

END &&

DELIMITER ;
Nota La última línea de este ejemplo cambia el DELIMITER volver al predeterminado ; valor.

Crear antes de activadores de eventos

En esta sección, veremos los diferentes tipos de activadores que se activan antes de una operación de base de datos. Estos incluyen el BEFORE INSERT , BEFORE UPDATE y BEFORE DELETE disparadores.

Creación de un disparador antes de insertar

Crearemos nuestro primer BEFORE INSERT generar. El activador se asegurará de que el precio minorista de un producto sea mayor que el precio de costo cada vez que se inserten elementos en los products. mesa. De lo contrario, el usuario de la base de datos obtendrá un error.

  1. Mientras todavía está en mysql > indicador, ingrese el siguiente comando:

    DELIMITER $$
    
    CREATE TRIGGER price_validator
    
    BEFORE INSERT
    
    ON products FOR EACH ROW
    
    IF NEW.cost_price>=NEW.retail_price
    
    THEN
    
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Retail price must be greater than cost price.';
    
    END IF $$
    
    DELIMITER ;
    
    • El código anterior define el nombre del disparador (price_validator ), hora (BEFORE ), evento (INSERT ), y la tabla (products ) para verse afectado.

    • Nuestro disparador usa el NEW palabra clave para comprobar el cost_price y retail_price antes de que se inserte un registro en los products tabla, usando el IF...THEN...END IF declaración.

    • Si el cost_price es mayor o igual al retail price , nuestros disparadores le dicen a MySQL que arroje una excepción personalizada que indique al usuario que rectifique el error.

  2. Para probar el disparador anterior, intente insertar un producto que viole la regla de validación:

    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('GAMING MOUSE PAD', '145.00', '144.00','LOCAL');
    

    Salida:

    ERROR 1644 (45000): Retail price must be greater than cost price.

    Los comandos de inserción anteriores deberían fallar porque el retail_price (144,00) no es mayor que el cost_price (145,00).

Creación de un disparador antes de la actualización

A continuación, crearemos un BEFORE UPDATE generar. Este activador evitará que los usuarios de la base de datos editen el nombre de un producto una vez que se haya insertado un producto en la base de datos. Si tiene varios usuarios trabajando en la base de datos, BEFORE UPDATE El disparador se puede usar para hacer que los valores sean de solo lectura, y esto puede evitar que los usuarios maliciosos o descuidados modifiquen los registros innecesariamente.

  1. Cree un nuevo product_name_validator dispara con el siguiente comando:

    DELIMITER $$
    
    CREATE TRIGGER product_name_validator
    
    BEFORE UPDATE
    
    ON products FOR EACH ROW
    
    IF NEW.product_name<>OLD.product_name
    
    THEN
    
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Product name is read-only and it can not be changed.';
    
    END IF $$
    
    DELIMITER ;
    

    Este disparador compara los valores del nuevo product_name (NEW.product_name ) y el nombre antiguo que ya está en la base de datos (OLD.product_name ). Si no coincide, se lanza una excepción.

  2. Para invocar el product_name_validator activador, podemos intentar actualizar el nombre del producto con el ID 1 :

    UPDATE products SET product_name='WIRELESS BLUETOOTH MOUSE' WHERE product_id='1';
    

    Salida:

    ERROR 1644 (45000): Product name is read-only and it can not be changed.

Definir un activador antes de eliminar

En esta sección, verá cómo puede definir un BEFORE DELETE activador para evitar que los usuarios eliminen registros específicos de una tabla.

  1. Para crear el prevent_delete desencadenar, ejecute el siguiente comando:

    DELIMITER $$
    
    CREATE TRIGGER prevent_delete
    
    BEFORE DELETE
    
    ON products FOR EACH ROW
    
    IF OLD.availability='ALL'
    
    THEN
    
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'The product can not be deleted because it is available in ALL stores.';
    
    END IF $$
    
    DELIMITER ;
    

    Este disparador evitará que los productos marcados con un valor de ALL en la columna de disponibilidad para que no se eliminen.

  2. A continuación, intente eliminar el primer producto de la tabla de productos y vea si se invocará el activador:

    DELETE FROM products WHERE product_id='1';
    

    Salida:

    ERROR 1644 (45000): The product can not be deleted because it is available in ALL stores.

Hemos analizado los diferentes disparadores que se invocan antes de una operación de base de datos. A continuación, veremos los otros tipos de activadores que se activan después de los eventos de la base de datos.

Creación de desencadenantes posteriores al evento

En un entorno de producción, es posible que desee que algunos disparadores se ejecuten automáticamente después de que ocurra un evento de la base de datos (por ejemplo, insertar registros en diferentes tablas). Los ejemplos a continuación demuestran cómo se pueden usar estos tipos de disparadores en nuestra base de datos de muestra.

Crear un disparador después de insertar

Este ejemplo crea un disparador llamado product_availability que inserta registros de mapeo en el products_to_stores mesa. Este activador se utiliza para aplicar la lógica empresarial; en particular, ayuda a definir la disponibilidad del producto para las diferentes tiendas.

  1. Ejecute el siguiente código para crear el product_availability generar. Dado que tenemos varias líneas de código en el cuerpo del disparador, usaremos un BEGIN...END bloque:

    DELIMITER $$
    
    CREATE TRIGGER product_availability
    
    AFTER INSERT
    
    ON products FOR EACH ROW
    
    BEGIN
    
    IF NEW.availability='LOCAL' then
    
    INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1');
    
    ELSE
    
    INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '1');
    
    INSERT INTO products_to_stores (product_id, store_id) VALUES (NEW.product_id, '2');
    
    END IF;
    
    END $$
    
    DELIMITER ;
    
    • Cuando se inserta un elemento en los products tabla, el activador comprobará la availability campo.

    • Si está marcado con el LOCAL valor, el producto estará disponible en una sola tienda.

    • Cualquier otro valor indicará al disparador que haga que el producto esté disponible para las dos tiendas que creamos anteriormente.

  2. Para ver la product_availability activador en acción, inserte los dos registros en la tabla de productos:

    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('BLUETOOTH KEYBOARD', '17.60', '23.30','LOCAL');
    INSERT INTO products (product_name, cost_price, retail_price, availability) VALUES ('DVB-T2 RECEIVE', '49.80', '53.40','ALL');
    
  3. Luego, consulta el products_to_stores tabla:

    SELECT * FROM products_to_stores;
    

    Debería ver un resultado similar al que se muestra a continuación:

    +--------+------------+----------+
    | ref_id | product_id | store_id |
    +--------+------------+----------+
    |      1 |          4 |        1 |
    |      2 |          5 |        1 |
    |      3 |          5 |        2 |
    +--------+------------+----------+
    3 rows in set (0.00 sec)

Definir un disparador posterior a la actualización

También se puede activar un disparador después de una UPDATE evento. Veremos cómo podemos aprovechar este tipo de activador para realizar un seguimiento de los cambios de precios en nuestra tienda a lo largo del tiempo.

  1. Crear un product_history_updater desencadenar ejecutando el siguiente comando:

    CREATE TRIGGER product_history_updater
    
    AFTER UPDATE
    
    ON products FOR EACH ROW
    
    INSERT INTO products_price_history (product_id, price_date, retail_price) VALUES (OLD.product_id, NOW(), NEW.retail_price);
    

    Este activador registra los cambios en el retail_price de un producto. en el products_price_history mesa.

    Nota A diferencia de los ejemplos anteriores, este disparador solo tiene una declaración en el cuerpo del disparador, por lo que no necesitamos cambiar el DELIMITER .
  2. Luego, intente actualizar el precio del primer producto ejecutando el siguiente comando:

    UPDATE products SET retail_price='36.75' WHERE product_id='1';
    
  3. A continuación, consulta el products_price_history tabla para ver si se registró el cambio de precio:

    SELECT * FROM products_price_history;
    

    Si el activador funcionó como se esperaba, debería obtener el siguiente resultado:

    +------------+---------------------+--------------+
    | product_id | price_date          | retail_price |
    +------------+---------------------+--------------+
    |          1 | 2020-01-28 11:46:21 |        36.75 |
    +------------+---------------------+--------------+
    1 row in set (0.00 sec)

Creación de un activador posterior a la eliminación

En algunos casos, es posible que desee registrar operaciones de eliminación después de que se haya producido una acción específica en la base de datos. Puede lograr esto usando AFTER DELETE disparador.

  1. Cree un nuevo product_archiver dispara con el siguiente comando:

    CREATE TRIGGER product_archiver
    
    AFTER DELETE
    
    ON products FOR EACH ROW
    
    INSERT INTO archived_products (product_id, product_name, cost_price, retail_price, availability) VALUES (OLD.product_id, OLD.product_name, OLD.cost_price, OLD.retail_price, OLD.availability);
    

    Este disparador archiva los productos eliminados en una tabla separada llamada archived_products . Cuando se elimina un artículo de los products principales tabla, nuestro activador lo registrará automáticamente en archived_products tabla para referencia futura.

  2. A continuación, elimine un producto de los products tabla y vea si se invocará el disparador:

    DELETE FROM products WHERE product_id='3';
    
  3. Ahora, si revisa los archived_products tabla, debería ver un registro:

    SELECT * FROM archived_products;
    

    Salida:

    +------------+--------------+------------+--------------+--------------+
    | product_id | product_name | cost_price | retail_price | availability |
    +------------+--------------+------------+--------------+--------------+
    |          3 | SMART WATCH  |      189.6 |        225.3 | LOCAL        |
    +------------+--------------+------------+--------------+--------------+
    1 row in set (0.00 sec)

Eliminación de un activador

Ha visto los diferentes tipos de activadores y cómo se pueden utilizar en un entorno de producción. A veces, es posible que desee eliminar un disparador de la base de datos.

Puede eliminar un disparador si ya no desea usarlo usando la siguiente sintaxis:

DROP TRIGGER IF EXISTS TRIGGER_NAME;
Nota El IF EXISTS La palabra clave es un parámetro opcional que solo elimina un disparador si existe.

Por ejemplo, para eliminar el product_archiving disparador que definimos arriba, use el siguiente comando:

DROP TRIGGER IF EXISTS product_archiver;

Salida:

Query OK, 0 rows affected (0.00 sec)
Precaución Tenga cuidado al eliminar tablas asociadas con disparadores. Una vez que se elimina una tabla de la base de datos MySQL, los activadores relacionados también se eliminan automáticamente.

Más información

Es posible que desee consultar los siguientes recursos para obtener información adicional sobre este tema. Si bien estos se proporcionan con la esperanza de que sean útiles, tenga en cuenta que no podemos garantizar la precisión o la puntualidad de los materiales alojados externamente.

  • Sintaxis y ejemplos de activación de MySQL