Pregunta

Al limpiar esta respuesta Aprendí un poco sobre los TRIGGER y los procedimientos almacenados en MySQL, pero me sorprendió, mientras que ANTES DE INSERTAR y ANTES DE ACTUALIZAR se activan podrían modificar los datos, aparentemente no pudieron causar que la inserción / actualización fallara (es decir, validación). En este caso particular, pude hacer que esto funcionara manipulando los datos de tal manera que causara un duplicado de la clave principal, lo que en este caso en particular tenía sentido, pero no necesariamente tiene sentido en un sentido general. p>

¿Es este tipo de funcionalidad posible en MySQL? En cualquier otro RDBMS (mi experiencia se limita a MySQL, por desgracia)? Tal vez una sintaxis de estilo de EXKE EXCEPTION ?

¿Fue útil?

Solución

De esto publicación de blog

  

MySQL Triggers: ¿Cómo abortar un INSERTAR, ACTUALIZAR o BORRAR con un   ¿desencadenar? En la #mysql de EfNet alguien   preguntó:

     

¿Cómo hago que un desencadenante aborte la operación si falla mi regla de negocios?

     

En MySQL 5.0 y 5.1 necesitas   recurrir a algún engaño para hacer una   desencadenar el fallo y entregar un significativo   mensaje de error. El MySQL almacenado   Preguntas frecuentes sobre el procedimiento dice esto sobre el error   manejo:

     

SP 11. ¿Los SP tienen una declaración de "aumento" para "generar errores de aplicación"? Lo siento, no en la actualidad. Las instrucciones SIGNAL y RESIGNAL estándar de SQL se encuentran en TODO.

     

Tal vez MySQL 5.2 incluya SIGNAL   declaración que hará este hack   Robado directamente de MySQL Stored   Procedimiento de programación obsoleto. Qué   es el hack? Vas a forzar   MySQL para intentar usar una columna que   no existe. ¿Feo? Sí. Lo hace   ¿trabajo? Claro.

CREATE TRIGGER mytabletriggerexample
BEFORE INSERT
FOR EACH ROW BEGIN
IF(NEW.important_value) < (fancy * dancy * calculation) THEN
    DECLARE dummy INT;

    SELECT Your meaningful error message goes here INTO dummy 
        FROM mytable
      WHERE mytable.id=new.id
END IF; END;

Otros consejos

Así es como lo hice. Tenga en cuenta que SET NEW = 'some error'; . MySQL le dirá que " Variable 'nuevo' no se puede establecer en el valor de 'Error: No se puede eliminar este elemento. Hay registros en la tabla de ventas con este artículo. '& Quot;

Puede capturar esto en su código y luego mostrar el error resultante :)

DELIMITER $
DROP TRIGGER IF EXISTS before_tblinventoryexceptionreasons_delete $
CREATE TRIGGER before_tblinventoryexceptionreasons_delete
BEFORE DELETE ON tblinventoryexceptionreasons
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblinventoryexceptionreasons = old.idtblinventoryexceptionreasons) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory exception reasons table with this item.';
  END IF;
END$
DELIMITER ;

DELIMITER $
DROP TRIGGER IF EXISTS before_storesalesconfig_delete $
CREATE TRIGGER before_storesalesconfig_delete
BEFORE DELETE ON tblstoresalesconfig
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblstoresales WHERE tblstoresales.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the sales table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinventory WHERE tblinventory.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory exceptions table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
  END IF;
END$
DELIMITER ;

DELIMITER $
DROP TRIGGER IF EXISTS before_tblinvoice_delete $
CREATE TRIGGER before_tblinvoice_delete
BEFORE DELETE ON tblinvoice
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblinvoice = old.idtblinvoice) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
  END IF;
END$
DELIMITER ;

Debido a que este artículo aparece en la parte superior cuando busco el manejo de errores en los activadores de MySQL, pensé que compartiría algunos conocimientos.

Si hay un error, puede forzar a MySQL a usar un SIGNAL , pero si no lo especifica como una clase como SQLEXCEPTION, entonces no ocurrirá nada, ya que no todos los SQLSTATE se consideran incorrectos, e incluso entonces debería asegurarse de RESIGNAL si tiene bloques BEGIN / END anidados .

Como alternativa, y probablemente aún más simple, dentro de su activador, declare un controlador de salida y renuncie a la excepción.

CREATE TRIGGER `my_table_AINS` AFTER INSERT ON `my_table` FOR EACH ROW
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
        RESIGNAL;
    DECLARE EXIT HANDLER FOR SQLWARNING
        RESIGNAL;
    DECLARE EXIT HANDLER FOR NOT FOUND
        RESIGNAL; 
    -- Do the work of the trigger.
END

Y si en su cuerpo se produce un error, se lo devolverá a la parte superior y saldrá con un error. Esto también se puede utilizar en procedimientos almacenados y otras cosas.

Esto funciona con cualquier versión 5.5+.

Esto abortará su INSERT al generar una excepción www.experts-exchange.com/Database/MySQL/Q_23788965.html )

DROP PROCEDURE IF EXISTS `MyRaiseError`$

CREATE PROCEDURE `MyRaiseError`(msg VARCHAR(62))
BEGIN
DECLARE Tmsg VARCHAR(80);
SET Tmsg = msg;
IF (CHAR_LENGTH(TRIM(Tmsg)) = 0 OR Tmsg IS NULL) THEN
SET Tmsg = 'ERROR GENERADO';
END IF;
SET Tmsg = CONCAT('@@MyError', Tmsg, '@@MyError');
SET @MyError = CONCAT('INSERT INTO', Tmsg);
PREPARE stmt FROM @MyError;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$

Uso:

call MyRaiseError('Here error message!');

No funciona en los desencadenantes (SQL dinámico no está permitido en función almacenada o activador)

Uso una solución muy sucia:

Si NEW.test = 1 entonces   CALL TEST_CANNOT_BE_SET_TO_1; terminara si;

Cuando test = 1 Mysql lanza la siguiente excepción:

la administración de PROCEDIMIENTOS.TEST_CANNOT_BE_SET_TO_1 no existe

No es sofisticado pero es rápido y útil.

en MS SQL puede hacer que funcione con la sintaxis adecuada:

IF UPDATE(column_name)
BEGIN
  RAISEERROR
  ROLLBACK TRAN
  RETURN
END

http://msdn.microsoft.com/en-us/magazine /cc164047.aspx

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top