20.3. Utilización de disparadores

MySQL 5.0

20.3. Utilización de disparadores

El soporte para disparadores se incluyó a partir de MySQL 5.0.2. Actualmente, el soporte para disparadores es básico, por lo tanto hay ciertas limitaciones en lo que puede hacerse con ellos. Esta sección trata sobre el uso de los disparadores y las limitaciones vigentes.

Un disparador es un objeto de base de datos con nombre que se asocia a una tabla, y se activa cuando ocurre un evento en particular para la tabla. Algunos usos para los disparadores es verificar valores a ser insertados o llevar a cabo cálculos sobre valores involucrados en una actualización.

Un disparador se asocia con una tabla y se define para que se active al ocurrir una sentencia , , o sobre dicha tabla. Puede también establecerse que se active antes o despues de la sentencia en cuestión. Por ejemplo, se puede tener un disparador que se active antes de que un registro sea borrado, o después de que sea actualizado.

Para crear o eliminar un disparador, se emplean las sentencias y . La sintaxis de las mismas se describe en Sección 20.1, “Sintaxis de y Sección 20.2, “Sintaxis de .

Este es un ejemplo sencillo que asocia un disparador con una tabla para cuando reciba sentencias . Actúa como un acumulador que suma los valores insertados en una de las columnas de la tabla.

La siguiente sentencia crea la tabla y un disparador asociado a ella:

mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;

La sentencia crea un disparador llamado que se asocia con la tabla . También se incluyen cláusulas que especifican el momento de activación, el evento activador, y qué hacer luego de la activación:

  • La palabra clave indica el momento de acción del disparador. En este caso, el disparador debería activarse antes de que cada registro se inserte en la tabla. La otra palabra clave posible aqui es .

  • La plabra clave indica el evento que activará al disparador. En el ejemplo, la sentencia causará la activación. También pueden crearse disparadores para sentencias y .

  • Las sentencia siguiente, , define lo que se ejecutará cada vez que el disparador se active, lo cual ocurre una vez por cada fila afectada por la sentencia activadora. En el ejemplo, la sentencia activada es un sencillo que acumula los valores insertados en la columna . La sentencia se refiere a la columna como , lo que significa “el valor de la columna que será insertado en el nuevo registro.

Para utilizar el disparador, se debe establecer el valor de la variable acumulador a cero, ejecutar una sentencia , y ver qué valor presenta luego la variable.

mysql> SET @sum = 0;
mysql> INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
mysql> SELECT @sum AS 'Total amount inserted';
+-----------------------+
| Total amount inserted |
+-----------------------+
| 1852.48               |
+-----------------------+

En este caso, el valor de luego de haber ejecutado la sentencia es , o .

Para eliminar el disparador, se emplea una sentencia . El nombre del disparador debe incluir el nombre de la tabla:

mysql> DROP TRIGGER account.ins_sum;

Debido a que un disparador está asociado con una tabla en particular, no se pueden tener múltiples disparadores con el mismo nombre dentro de una tabla. También se debería tener en cuenta que el espacio de nombres de los disparadores puede cambiar en el futuro de un nivel de tabla a un nivel de base de datos, es decir, los nombres de disparadores ya no sólo deberían ser únicos para cada tabla sino para toda la base de datos. Para una mejor compatibilidad con desarrollos futuros, se debe intentar emplear nombres de disparadores que no se repitan dentro de la base de datos.

Adicionalmente al requisito de nombres únicos de disparador en cada tabla, hay otras limitaciones en los tipos de disparadores que pueden crearse. En particular, no se pueden tener dos disparadores para una misma tabla que sean activados en el mismo momento y por el mismo evento. Por ejemplo, no se pueden definir dos o dos en una misma tabla. Es improbable que esta sea una gran limitación, porque es posible definir un disparador que ejecute múltiples sentencias empleando el constructor de sentencias compuestas luego de . (Más adelante en esta sección puede verse un ejemplo).

También hay limitaciones sobre lo que puede aparecer dentro de la sentencia que el disparador ejecutará al activarse:

  • El disparador no puede referirse a tablas directamente por su nombre, incluyendo la misma tabla a la que está asociado. Sin embargo, se pueden emplear las palabras clave y . se refiere a un registro existente que va a borrarse o que va a actualizarse antes de que esto ocurra. se refiere a un registro nuevo que se insertará o a un registro modificado luego de que ocurre la modificación.

  • El disparador no puede invocar procedimientos almacenados utilizando la sentencia . (Esto significa, por ejemplo, que no se puede utilizar un procedimiento almacenado para eludir la prohibición de referirse a tablas por su nombre).

  • El disparador no puede utilizar sentencias que inicien o finalicen una transacción, tal como , , o .

Las palabras clave y permiten acceder a columnas en los registros afectados por un disparador. ( y no son sensibles a mayúsculas). En un disparador para , solamente puede utilizarse ; ya que no hay una versión anterior del registro. En un disparador para sólo puede emplearse , porque no hay un nuevo registro. En un disparador para se puede emplear para referirse a las columnas de un registro antes de que sea actualizado, y para referirse a las columnas del registro luego de actualizarlo.

Una columna precedida por es de sólo lectura. Es posible hacer referencia a ella pero no modificarla. Una columna precedida por puede ser referenciada si se tiene el privilegio sobre ella. En un disparador , también es posible cambiar su valor con = si se tiene el privilegio de sobre ella. Esto significa que un disparador puede usarse para modificar los valores antes que se inserten en un nuevo registro o se empleen para actualizar uno existente.

En un disparador , el valor de para una columna es 0, no el número secuencial que se generará en forma automática cuando el registro sea realmente insertado.

y son extensiones de MySQL para los disparadores.

Empleando el constructor , se puede definir un disparador que ejecute sentencias múltiples. Dentro del bloque , también pueden utilizarse otras sintaxis permitidas en rutinas almacenadas, tales como condicionales y bucles. Como sucede con las rutinas almacenadas, cuando se crea un disparador que ejecuta sentencias múltiples, se hace necesario redefinir el delimitador de sentencias si se ingresará el disparador a través del programa mysql, de forma que se pueda utilizar el caracter '' dentro de la definición del disparador. El siguiente ejemplo ilustra estos aspectos. En él se crea un disparador para , que verifica los valores utilizados para actualizar cada columna, y modifica el valor para que se encuentre en un rango de 0 a 100. Esto debe hacerse en un disparador porque los valores deben verificarse antes de emplearse para actualizar el registro:

mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
    -> FOR EACH ROW
    -> BEGIN
    ->     IF NEW.amount < 0 THEN
    ->         SET NEW.amount = 0;
    ->     ELSEIF NEW.amount > 100 THEN
    ->         SET NEW.amount = 100;
    ->     END IF;
    -> END;//
mysql> delimiter ;

Podría parecer más fácil definir una rutina almacenada e invocarla desde el disparador utilizando una simple sentencia . Esto sería ventajoso también si se deseara invocar la misma rutina desde distintos disparadores. Sin embargo, una limitación de los disparadores es que no pueden utilizar . Se debe escribir la sentencia compuesta en cada donde se la desee emplear.

MySQL gestiona los errores ocurridos durante la ejecución de disparadores de esta manera:

  • Si lo que falla es un disparador , no se ejecuta la operación en el correspondiente registro.

  • Un disparador se ejecuta solamente si el disparador (de existir) y la operación se ejecutaron exitosamente.

  • Un error durante la ejecución de un disparador o deriva en la falla de toda la sentencia que provocó la invocación del disparador.

  • En tablas transaccionales, la falla de un disparador (y por lo tanto de toda la sentencia) debería causar la cancelación (rollback) de todos los cambios realizados por esa sentencia. En tablas no transaccionales, cualquier cambio realizado antes del error no se ve afectado.