¿Es posible predecir las operaciones que siguen a una cascada eliminar automáticamente? En mi software, me gustaría darle al usuario una advertencia con detalles sobre los datos que se eliminarían en ese momento.¿Quieres simular una CASCADA DELETE en MySQL?
Respuesta
Se puede hacer una copia de la base de datos y poner disparadores en la tabla after delete
DELIMITER $$
CREATE TRIGGER ad_table1_each AFTER DELETE ON table1 FOR EACH ROW
BEGIN
INSERT INTO log VALUES (null /*autoinc id*/
, 'table1' /*tablename*/
, old.id /*tableid*/
, concat_ws(',',old.field1,old.field2 /*CSV's of fields*/
, NOW() /*timestamp*/
, 'delete'); /*what action*/
REPLACE INTO restore_table1 VALUES (old.id,
, old.field1
, old.field2
, ...);
END $$
DELIMITER ;
El registro es sólo una tabla con los siguientes campos:
id integer autoincrement primary key
tablename varchar(45)
table_id integer
fields varchar(6000)
delete_time timestamp
action enum('insert','update','delete')
Si lo hace un SELECT @last_id:= max(id) FROM log
antes la cascada de eliminación en la copia.
Luego puede hacer un SELECT * FROM log WHERE id > @last_id
y obtener todas las filas que se eliminarán en la cascada.
Después de eso, puede usar restore_table1 para recrear las filas que se eliminaron en la cascada en la base de datos de copias.
Creo que podría usar la solución de activación de Johan en combinación con una transacción que revierte. Esto evita tanto la necesidad de una segunda base de datos como la restauración manual de las entradas eliminadas.
- añadir el gatillo y la tabla de registro
- para cada intento de eliminación se inicia una transacción y eliminar las entradas
- presentar la información del registro a su usuario para su aprobación
- si el usuario está de acuerdo en cometer el transacción, de lo contrario Rollback
El único problema es, si el motor que inicia sesión también admite transacciones, que el registro también se retrotraerá, por lo que debe usar un motor no transaccional para el registro, como MyISAM. – Johan
La idea de transacción es genial. De hecho, yo no usaría triggers ni un log para eso. Simularía la eliminación y luego la reversión. – user694971
@ user694971: Creo que necesita el registro si desea mostrar las entradas eliminadas al usuario. Sin él, solo puede mostrar las entradas restantes, a menos que la lógica de la aplicación pueda resolverlo. – Stefan
escribí un corte muy rápido que hace exactamente lo que necesita en PHP, ya que quería hacer exactamente lo mismo y no he encontrado ningún recurso para esa línea.
Puede ser demasiado tarde para usted, pero puede ayudar a otros.
function get_referencing_foreign_keys ($database, $table) {
$query = 'SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = "'.$database.'" AND REFERENCED_TABLE_NAME = '.esc($table);
$result = rquery($query);
$foreign_keys = array();
while ($row = mysql_fetch_row($result)) {
$foreign_keys[] = array('database' => $row[0], 'table' => $row[1], 'column' => $row[2], 'reference_column' => $row[3]);
}
return $foreign_keys;
}
function get_foreign_key_deleted_data_html ($database, $table, $where) {
$data = get_foreign_key_deleted_data ($database, $table, $where);
$html = '';
foreach ($data as $key => $this_data) {
$html .= "<h2>$key</h2>\n";
$html .= "<table>\n";
$i = 0;
foreach ($this_data as $value) {
if($i == 0) {
$html .= "\t<tr>\n";
foreach ($value as $column => $column_value) {
$html .= "\t\t<th>".htmlentities($column)."</th>\n";
}
$html .= "\t</tr>\n";
}
$html .= "\t<tr>\n";
foreach ($value as $column => $column_value) {
$html .= "\t\t<td>".htmlentities($column_value)."</td>\n";
}
$html .= "\t</tr>\n";
$i++;
}
$html .= "</table>\n";
}
return $html;
}
function get_foreign_key_deleted_data ($database, $table, $where) {
$GLOBALS['get_data_that_would_be_deleted'] = array();
$data = get_data_that_would_be_deleted($database, $table, $where);
$GLOBALS['get_data_that_would_be_deleted'] = array();
return $data;
}
function get_data_that_would_be_deleted ($database, $table, $where, $recursion = 100) {
if($recursion <= 0) {
die("Deep recursion!");
}
if($recursion == 100) {
$GLOBALS['get_data_that_would_be_deleted'] = array();
}
if($table) {
if(is_array($where)) {
$foreign_keys = get_referencing_foreign_keys($database, $table);
$data = array();
$query = 'SELECT * FROM `'.$table.'`';
if(count($where)) {
$query .= ' WHERE 1';
foreach ($where as $name => $value) {
$query .= " AND `$name` = ".esc($value);
}
}
$result = rquery($query);
$to_check = array();
while ($row = mysql_fetch_row($result)) {
$new_row = array();
$i = 0;
foreach ($row as $this_row) {
$field_info = mysql_fetch_field($result, $i);
$new_row[$field_info->name] = $this_row;
foreach ($foreign_keys as $this_foreign_key) {
if($this_foreign_key['reference_column'] == $field_info->name) {
$to_check[] = array('value' => $this_row, 'foreign_key' => array('table' => $this_foreign_key['table'], 'column' => $this_foreign_key['column'], 'database' => $this_foreign_key['database']));
}
}
$i++;
}
$GLOBALS['get_data_that_would_be_deleted'][$table][] = $new_row;
}
foreach ($to_check as $this_to_check) {
if(isset($this_to_check['value']) && !is_null($this_to_check['value'])) {
get_data_that_would_be_deleted($database, $this_to_check['foreign_key']['table'], array($this_to_check['foreign_key']['column'] => $this_to_check['value']), $recursion - 1);;
}
}
$data = $GLOBALS['get_data_that_would_be_deleted'];
return $data;
} else {
die("\$where needs to be an array with column_name => value pairs");
}
} else {
die("\$table was not defined!");
}
}
Imagínese que tengo una tabla llamada "mesa" en la base de datos "DB" y quiero borrar el uno con el identificador 180, entonces yo diría:
print(get_foreign_key_deleted_data_html('db', 'table', array('id' => 180)));
e imprime una tabla completa con todas las filas y todos los valores que se eliminarán.
Pero como he dicho, este es un hack muy, muy rápido y sucio. Me agradaría cualquier informe de errores (¡y seguramente hay muchos de ellos!).
- 1. nhibernate "en cascada =" all-delete-orphan" error
- 2. MySQL en eliminar cascada. Ejemplo de prueba
- 3. Simular consultas de mysql
- 4. mysql delete on join?
- 5. desencadenantes en cascada en SQLite
- 6. MySQL restricciones de clave externa, eliminar en cascada
- 7. CASCADE DELETE una sola vez
- 8. MySQL LÍMITE en la declaración DELETE
- 9. ¿Cómo puedo simular OFFSET en una instrucción UPDATE de MySQL?
- 10. Cómo simular una impresión en un procedimiento almacenado de MySQL
- 11. ¿Cómo puedo simular una declaración de impresión en MySQL?
- 12. función de retardo Simular en MySQL
- 13. ¿Cómo configurar eliminaciones en cascada en MySQL workbench?
- 14. NHibernate, "On Delete Cascade", elimina en cascada las filas en tablas relacionadas?
- 15. Mantenerse ágil en una cascada
- 16. Dilema: Cascade delete or Join delete
- 17. Oracle cascade delete
- 18. Python MySQL - SELECT funciona, pero no DELETE?
- 19. Hibernate no genera cascada
- 20. Desencadenar llamadas en cascada eliminando
- 21. ¿Puede un disparador MySQL simular una restricción CHECK?
- 22. No se puede obtener en mysql delete query to
- 23. Cómo usar delete cascade en MySQL MyISAM storage engine?
- 24. No se puede crear el desencadenador Eliminar porque la tabla tiene una LLAVE EXTRAÑA con DELETE en cascada
- 25. Hibernate Delete Cascade
- 26. Entity Framework en eliminar cascada
- 27. Obtenga una autorrefensa en una consulta DELETE
- 28. Cascading Soft Delete
- 29. nhibernate no Eliminar en cascada los niños
- 30. Quieres abrir una ventana con una acción en CakePHP
Buena pregunta, estoy interesado en la respuesta también. – Alp
El único enfoque razonable en el que puedo pensar actualmente es 'MOSTRAR COLUMNAS COMPLETAS DE 'y luego recorrer las tablas correspondientes ... (hardcodes fkey_names => table_names ...) –
user694971