2011-12-30 19 views
12

Quiero proteger algunas filas de la eliminación y prefiero hacerlo mediante desencadenadores en lugar de la lógica de mi aplicación. Estoy usando la base de datos MySQL.Proteger fila de eliminación en MySQL

Lo que se me ocurrió es la siguiente:

DELIMITER $$ 

DROP TRIGGER `preserve_permissions`$$ 

USE `systemzarzadzaniareporterami`$$ 

CREATE TRIGGER `preserve_permissions` 
AFTER DELETE ON `permissions` 
FOR EACH ROW 
BEGIN 
IF old.`userLevel` = 0 AND old.`permissionCode` = 164 THEN 
    INSERT INTO `permissions` SET `userLevel`=0, `permissionCode`=164; 
END IF; 
END$$ 

DELIMITER ; 

pero me da un error cuando se utiliza borrar:

DELETE FROM `systemzarzadzaniareporterami`.`permissions` 
WHERE `userLevel` = 0 AND `permissionCode` = 164; 

Error Code: 1442. Can't update table 'permissions' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. 

¿Hay otra manera de hacer tal cosa?

Respuesta

13

Una solución sería crear una tabla secundaria con una clave externa en la tabla de permisos y agregar filas dependientes que hagan referencia a las filas individuales para las que desea bloquear la eliminación.

CREATE TABLE preserve_permissions (
    permission_id INT PRIMARY KEY, 
    FOREIGN KEY (permission_id) REFERENCES permissions (permission_id) 
); 

INSERT INTO perserve_permissions (permission_id) VALUES (1234); 

ahora no se puede eliminar la fila de los permisos con id 1234, porque violaría la relación de clave externa.

Si realmente desea hacerlo con un desencadenante, en lugar de volver a insertar una fila cuando alguien intenta eliminarlo, simplemente anule la eliminación. MySQL 5.5 tiene la característica SIGNAL para generar un SQLEXCEPTION en un disparador o un procedimiento almacenado.

Si utiliza MySQL 5.0 o 5.1, no puede usar SIGNAL pero puede usar un truco que es declarar una variable INT local en su desencadenador e intentar asignarle un valor de cadena. Este es un conflicto de tipo de datos por lo que arroja un error y aborta la operación que generó el desencadenador. El truco más ingenioso es especificar un mensaje de error apropiado en la cadena que intentas meter en el INT, ¡porque esa cadena se informará en el error! :-)

10

Crea una nueva tabla y crea una clave externa. Establezca la clave externa en delete - restrict.

CONSTRAINT FOREIGN KEY fk_restriction (restriction_col) 
table_to_restrict (restricted_id) ON DELETE RESTRICT ON UPDATE CASCADE 

Nota: Esto no es posible hacer con MyISAM, el agujero negro, etc motor. Usar con InnoDB y motores descendientes.

Cuestiones relacionadas