En esta vitamina aprenderás a hacer actualizaciones y arrastrados con condición dinámica en Velneo.
1. Planteando el problema
Los triggers (o eventos de tabla) y las actualizaciones (o macro-triggers automáticos) son dos funcionalidades muy utilizadas en nuestras bases de datos ya que nos aportan gran potencia de forma sencilla para gestionar cambios tanto en el registro que está siendo creado, modificado o eliminado como en los registros de otras tablas maestras o plurales enlazadas o de registros de tablas a las que accedemos mediante código.
La facilidad para crear las actualizaciones de tablas lleva implícito un efecto secundario y es que son disparados de forma automática cuando se producen cambios en campos que intervienen en la actualización, algo que es muy agradecido pero que en algunos casos puede resultar un problema. Veamos algunos ejemplos:
[pl_alertbox type=»warning»]
Caso A
Tenemos una tabla con actualizaciones que acumula valores en tablas maestras, pero cuando el alta se produce a través de un proceso de importación, no queremos que se ejecuten dichas actualizaciones porque duplican los valores que ya han sido importados en las tablas maestras.[/pl_alertbox]
[pl_alertbox type=»warning»]
Caso B
Tenemos una tabla de movimientos de almacén donde en el trigger posterior al alta, modificación o baja, cada vez que cambia el campo cantidad o precio se fuerza el recálculo «en cascada» de todos los registros, desde el modificado hasta el último de ese artículo calculando la existencia y el valor del almacén en cada movimiento. Pero nos gustaría que cuando hacemos cambios globales a todos los registros de un artículo sólo se realizase el cálculo de existencia y valoración de almacén una vez, ya que si se lanza por cada registro el número de veces que es modificado cada registro es el resultado de un cálculo factorial, lo que supone una gran pérdida de rendimiento en la ejecución de estos procesos.[/pl_alertbox]
2. Planteando la solución
Desde el punto de vista de teórico la solución es muy sencilla. Evitar que se ejecuten los triggers y actualizaciones siempre, y que sólo se ejecuten cuando nosotros lo deseemos.
Desde el punto de vista práctico parece en principio sencillo ya que las actualizaciones tienen una propiedad «condición» que permite indicar la fórmula a calcular con la condición que debe cumplirse para su ejecución, y los triggers son código en el podemos también usar sentencias de condición para evitar su ejecución. El problema aún así persiste ya que la condición para que no se ejecuten debe ser dinámica, es decir, no depende de los datos del registro sino que depende de las circunstancias en las que se producen las operaciones de alta, baja o modificación. Es decir, desde ciertos procesos, funciones o formularios sí deben ejecutarse y desde otros no.
3. Programando la solución
La solución pasa por conseguir que el registro sea «consciente» de si deben o no ejecutarse los triggers y actualizaciones, y que pase esa información a los triggers y actualizaciones para que actúen en consecuencia. Eso lo vamos a conseguir realizando los siguientes pasos:
- Añadir en la tabla un campo booleano, por ejemplo #CAL_ARR (Calcular datos arrastrados).
- Añadir en la tabla una variable local booleana, por ejemplo #CAL_ARR (Calcular datos arrastrados).
- En los triggers anteriores a alta, baja o modificación añadiremos el siguiente código para controlar si el campo booleano llega con el valor 1, en cuyo caso lo que hacemos es poner a 1 la variable local que será la que usemos a partir de este momento para condicionar la ejecución en triggers y actualizaciones, y el campo a 0 para evitar cualquier conflicto con un bucle infinito de actualizaciones en cascada.
- Ahora sólo nos queda usar la variable local para controlar los componentes de actualización y el código de los triggers que deseamos ejecutar.
- Ahora sólo queda que cuando vayas a crear, modificar o eliminar un registro de esta tabla, tanto desde un formulario, como de un manejador de evento, función, proceso, etc. pongas el valor del campo #CAL_ARR a 1 (si deseas que se ejecuten las actualizaciones y los cálculos arrastrados) o dejarlo a 0 (si deseas que no se ejecuten las actualizaciones y los cálculos arrastrados). Es importante que evites poner a 1 el valor de este campo en un trigger pues por error puedes llegar a provocar un bucle infinito o un desbordamiento del stack.
4. Conclusión
Práctico y sencillo de programar, podrás optimizar tu aplicación para que ejecuten los bucles de actualización de cálculos arrastrados y las actualizaciones el menor número de veces posible, independientemente de que las operaciones en la tabla se lancen desde objetos de interfaz, procesos en primer plano o en el servidor. Desgraciadamente en Velneo 6x no contamos con variables locales a nivel de tabla por lo que no podemos utilizar esta técnica.
Nota:
Si tu tabla tiene millones de registros y no te gusta usar un byte para obtener esta funcionalidad también puedes utilizar otro campo de la tabla donde puedas grabar al principio o al final del mismo un carácter o etiqueta que te identifique que se deben ejecutar los arrastrados y las actualizaciones. Por ejemplo, utilizar un campo #REF (Referencia) en el que pondríamos al principio de su contenido el símbolo «#». En el trigger anterior si aparece ese símbolo actualizamos el campo referencia quitándoselo y poniendo a 1 la variable local para ejecutar los arrastrados, de esta forma nos ahorramos un campo.
Fer dice
Tendrás que poner el campo a 1 en algún momento, no? Cuando se ejecute el proceso..supongo
Gracias por la píldora
jarboleya dice
Gracias por tu comentario Fer.
Por si no quedaba claro como debía funcionar he añadido el punto 5 en el apartado de programando la solución explicando donde se debe poner a 1 el campo.
Charles dice
Hola, somos dos mujeres de Medellin Colombia, demeosas participar del diplomado que ofrecen en este momento para Tarapia Narrativa. Necesitamos conocer la direccif3n del lugar donde se impartire1n los cursos para revisar opciones de alojamiento. Si nos pueden sugerir algunos lugares lugares econf3micos les agradecemos. Necesitamos realizar muy pronto un presupuesto para saber si podemos o no inscribirnos.De otro lado, al intentar hacer una preinscripcif3n sf3lo nos da opcif3n pais Perfa, nos pueden orientar en este procedimiento?gracias
portiella dice
Dicen las buenas lenguas que hubo una persona que logró condicionar el arrastrado de hermanos con V6 de forma elegante y fino en un programa llamado Vulcano 😉
jarboleya dice
Jejeje seguro que no son malas lenguas, …. Serán viejas lenguas … 😉
Henry Villegas C dice
Buenas tardes ingeniero:
En un soporte interno me acaban de referenciar ésta solución, y realmente es la mas óptima de las que he visto, pero si quiero corroborar dos (2) puntos:
1. ¿El proceso FIC_BUL_CAL_ARR es un proceso recursivo?. En caso de ser así, ¿Se debe volver el campo #CAL_ARR nuevamente a cero (0) para que después, en el primero proceso, no tome la variable el valor de uno (1)?
2. ¿La actualización que se realiza es a un maestro?
Gracias por su información.
jarboleya dice
Hola Orlando.
En realidad el proceso FIC_BUL_CAL_ARR no es recursivo, lo que sucede es que ese proceso realiza modificaciones en registros de la tabla de movimientos de almacén MOV, lo que produce que se vuelvan a ejecutar los triggers de la tabla y correríamos el peligro de entrar en un bucle sin fin. Precisamente para evitar eso se pone el campo CAL_ARR a cero en todos los casos para que no se produzca el citado bucle, y sólo se pone a 1 ese campo cuando queremos iniciar el cálculo de arrastrados, es decir sólo en la actualización del primer registro.
Las actualizaciones siempre se realizan a punteros a tabla maestra, en este caso la tabla de existencias, o estadísticas serían los maestros más habituales a ser actualizados.
Manu dice
Buenas jarboleya.
estoy usando esta solución pero tengo un problema con las actualizaciones a la tabla de stock. La he condicionado para que solo se lance la actualización si es el último registro de la tabla de movimientos, así evito actualizaciones innecesarios.
Otro problema es que la tabla de existencias, a su vez acumula el stock en el artículo.
¿Dónde se lanza el proceso? en el trigger anterior o en el posterior.
Ahora lo tengo en el posterior y en el anterior pongo el campo a 0, el problema es que me actualiza dos veces la tabla de existencias y duplica el stock en los artículos.
Saludos