Triggers o eventos de tabla: Qué son y cómo funcionan

¿Sabes que con los triggers o eventos de tabla puedes realizar acciones antes, durante o después de dar de alta, modificar o eliminar un registro?

Primero vamos a definir que son los triggers o eventos de tabla.

Según la definición de Velneo

Un trigger es un proceso definido por el programador que es ejecutado automáticamente al producirse el evento al que hace referencia.

Desde este enlace puedes acceder a la ayuda oficial sobre los triggers.

Consideraciones importantes sobre los triggers

Antes de ver los tipos de triggers que Velneo pone a nuestra disposición, déjame que te cuente 2 consideraciones muy importantes por si hay algún despistado en la sala… “que haberlos haylos”.

  • Son “eventos de tabla”… por lo tanto se ejecutan en el servidor. No pongas ninguna instrucción que requiera la interacción con el usuario, puesto que no lo verá.
  • Cualquier cambio que se desee realizar en la ficha en la que nos encontremos, siempre deberá ser hecho antes de su grabación, es decir, en el trigger anterior.

Avisado quedas… ¿Vale Rodolfo?

Tipos de triggers o eventos de tabla

Un trigger es un subobjeto del objeto tabla por lo tanto para crearlo tendremos que hacerlo desde el panel de subobjetos de la tabla en cuestión o bien desde la barra de opciones de menú de dicha tabla.

Al dar de alta un nuevo trigger, nos aparece el siguiente formulario:

Tipos de Triggers

Como podéis ver, tenemos 9 triggers disponibles:

  • 3 correspondientes al alta de una ficha.
  • 3 correspondientes a la modificación de una ficha
  • 3 correspondientes a la baja de una ficha.

El tipo de trigger a utilizar dependerá de 2 factores:

  • Si queremos modificar en el proceso la ficha en la que estamos posicionados
  • Si queremos realizar las acciones antes o después de que se lancen las actualizaciones programadas en la tabla.

Además, sobra decirlo, la primera instrucción del proceso tendrá origen ficha.

  • Alta: Anterior a un alta de ficha: el proceso se lanza cuando la ficha todavía no ha sido dada de alta en la base de datos, por lo que podemos realizar cambios en sus campos.
  • Alta: Interno a un alta de ficha: el proceso se lanza cuando la ficha ya ha sido dada de alta en la base de datos, por lo que no podemos realizar cambios en sus campos, pero todavía no se han lanzado las actualizaciones.
  • Alta: Posterior a un alta de ficha: el proceso se lanza cuando la ficha ya ha sido dada de alta en la base de datos, y además ya se han lanzado las actualizaciones.
  • Modificación: Anterior a una modificación de ficha: el proceso se lanza cuando la ficha todavía no ha sido modificada en la base de datos, por lo que podemos realizar cambios en sus campos.
  • Modificación: Interno a una modificación de ficha: el proceso se lanza cuando la ficha ya ha sido modificada en la base de datos, por lo que no podemos realizar cambios en sus campos, pero todavía no se han lanzado las actualizaciones.
  • Modificación: Posterior a una modificación de ficha:  el proceso se lanza cuando la ficha ya ha sido modificada en la base de datos, y además ya se han lanzado las actualizaciones.
  • Baja: Anterior a una baja de ficha: el proceso se lanza cuando la ficha todavía no ha sido eliminada de la base de datos.
  • Baja: Interno a una baja de ficha: el proceso se lanza cuando la ficha ya ha sido eliminada de la base de datos, pero todavía no se han lanzado las actualizaciones.
  • Baja: Posterior a una baja de ficha: el proceso se lanza cuando la ficha ya ha sido eliminada de la base de datos y además ya se han lanzado las actualizaciones.

Por si no ha quedado todavía lo suficientemente claro, te dejo un esquema que lo aclara mas.

Esquema sobre triggers

 

¿Alguna duda sobre los triggers o eventos de tabla?

Cuéntamela dejándome un comentario mas abajo.

La entrada Triggers o eventos de tabla: Qué son y cómo funcionan aparece primero en AyudaVelneo.

Consultorio Velneo: ¡Actualizaciones al poder!

Muy interesante la pregunta que me hace David Cueva desde Juarez (México) y que creo que se puede resolver mediante la creación de 3 campos y 1 actualización ¿no te lo crees?.. Sigue leyendo.

Actualizaciones al poder

La pregunta en cuestión es la siguiente:

Tengo un formulario de mantenimiento a x unidad…en el tengo datos de la unidad a servir, fecha, y un boleano que me indicara cuando el mantenimiento actual..esta terminado….abajo….una vista de datos donde esta la rejilla de lineas de mantenimiento (editable)…donde tengo el servicio a dar…y entre otras cosas un campo de finalizado…..
lo que no puedo lograr es que al momento que todas las lineas (servcios), esten en finalizado si….en ese instante me habilite el campo Terninado en el formulario…si hay algun servicio sin terminar…debe permanecer deshabilitado…
Mediante control de evento y eventos….lo hace..pero a destiempo…no en tiempo real…..
Antes de continuar, es muy recomendable que, si no lo has hecho ya, leas este artículo acerca de las actualizaciones.

Definiendo el problema

Básicamente David tiene un registro (maestro) en el que hay que cambiar un campo de tipo booleano en función de si todas sus líneas (plural) están en estado terminado o no (te recomiendo leer también este otro post sobre las relaciones entre tablas).

David lo ha conseguido mediante maneadores de evento pero el problema es que no consigue que el valor del campo booleano se actualice en tiempo real.

Siempre digo que todo lo que podamos hacer en el proyecto de datos, es recomendable hacerlo ahí. Velneo se encargará de realizar las operaciones necesarias para actualizar los registros.

Pues vamos a ello…

Creando los campos necesarios

Para aplicar la solución, en el registro del mantenimiento vamos a crear dos campos de tipo numérico:

  • NUM_LIN_TOT: iremos acumulando en este campo el número de líneas que tiene el registro en cuestión.
  • NUM_LIN_TER: iremos acumulando en este campo el número de líneas que estén terminadas.

Además vamos a modificar el contenido inicial del campo booleano (le llamaremos B_TER) que nos indica si el mantenimiento está terminado o no:

  • choose(#NUM_LIN_TOT= #NUM_LIN_TER, 1, 0)

De esta forma conseguiremos que el campo se marque como “Terminado” cuando el nº de líneas terminadas sea igual al nº de líneas totales.

Velneo se encarga del resto: Actualizaciones al poder

Ahora sólo nos falta que los campos para el número de líneas se vayan actualizando de forma automática.
Para ello vamos a crear una actualización en la tabla de líneas de mantenimiento que actualice el maestro de mantenimientos.
Una vez creada, vamos a dar de alta dos componentes:
Nº de líneas totales
Actualización sencilla… cada vez que demos de alta una línea del mantenimiento… se acumula 1 en el campo NUM_LIN_TOT.

Nº de líneas terminadas

Mediante este componente de actualización, iremos añadiendo 1 al nº de líneas terminadas pero solamente cuando la línea esté terminada (la condicionamos a que el campo B_TER esté a 1).

Conclusión

Pues si esperabas algo mas de dificultad… lo dejaremos para otro día. Con estas sencillas instrucciones, David conseguirá lo que se propone.

Cuando el valor del campo NUM_LIN_TER sea igual al del campo NUM_LIN_TOT, querrá decir que todas las líneas estarán terminadas y por tanto el campo booleano B_TER se marcará a 1.

Ya sabes que si tienes alguna duda sobre Velneo, puedes hacérmela llegar a través del formulario de contacto e intentaré responderla.

Déjame un comentario mas abajo y comenzamos el debate.

La entrada Consultorio Velneo: ¡Actualizaciones al poder! aparece primero en AyudaVelneo.

Actualizaciones y arrastrados con condición dinámica en Velneo V7

VITAMINA – 6

En esta vitamina aprenderás a hacer actualizaciones y arrastrados con condición dinámica en Velneo V7.

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:

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.

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.

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:

  1. Añadir en la tabla un campo booleano, por ejemplo #CAL_ARR (Calcular datos arrastrados).
     
  2. Añadir en la tabla una variable local booleana, por ejemplo #CAL_ARR (Calcular datos arrastrados).
     
  3. 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.
     Cálculo de arrastrados - trigger anterior 
  4. 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.
     Cálculo de arrastrados - trigger posterior
     Actualizaciones y arrastrados con condición dinámica en Velneo V7
     
  5. 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.

 

Si te ha gustado este artículo, por favor compártelo con los tuyos en las redes sociales

The post Actualizaciones y arrastrados con condición dinámica en Velneo V7 appeared first on Lógica mente Velneo V7.

Actualizaciones en tablas en memoria

Actualizaciones en tablas en memoria

En Velneo V7 encontrarás la posibilidad de hacer uso de actualizaciones para tablas en memoria.

Las tablas en memoria, además de actualizar otras tablas en memoria en el mismo plano, permiten actualizar tablas en disco en el servidor, permitiendo programar de forma sencilla sistemas de estadísticas, importaciones de datos, etc., que requieran de actualizaciones a tablas en disco con persistencia, desechando los datos en memoria.


Las actualizaciones entre tablas en memoria tienen el mismo funcionamiento que entre tablas en disco, pero debemos tener en cuenta el entorno de las las tablas en memoria. Este puede ser local o en el servidor.

Es decir, el cliente puede tener sus tablas en memoria (trabajando con procesos en 1º plano) y las actualizaciones se realizarán sobre esas tablas en local.

Al mismo tiempo, podremos trabajar con tablas en memoria en el servidor (compartidas por todos los usuarios) y las actualizaciones correspondientes se dispararán entra esas tablas en el servidor, de igual forma a como actúan las actualizaciones en tablas en disco.

Y ahora, como novedad, tenemos la posibilidad de actualizar desde tablas en memoria hacia tablas en disco, tanto desde local como en el servidor.

Así, trabajaremos, por ejemplo en el cliente en local, para dar de alta registros en memoria de forma ágil, que a su vez lanzarán actualizaciones contra tablas en disco en el servidor que serán los datos que realmente nos interesa mantener.

Esto es muy útil cuando trabajamos con datos volátiles, sean estos en gran número o pocos, de los que únicamente queremos guardar acumulados o estadísticas. Por ejemplo, será útil en importaciones, estadísticas, modelos ágiles cliente-servidor tipo TPV’s, etc., permitiéndonos manejar gran cantidad de datos en el cliente sin necesidad de enviar al servidor más que los datos que realmente queremos que se guarden.

La incorporación de actualizaciones a las tablas en memoria y la novedad de poder actualizar desde estas a tablas en disco en el servidor, incluidas desde la versión 7.8, hacen transparente la interacción entre tablas en memoria y en disco, facilitando el desarrollo de nuestras aplicaciones.

¿Cuándo se disparan las actualizaciones?

La definición de actualización que encontramos en la ayuda dice:

“Una actualización es un subobjeto de tabla que permite actualizar el valor de los campos de un registro de una tabla enlazada cada vez que se produce un alta, una modificación o una baja en la tabla origen en la que definimos las actualizaciones.”

La cuestión que se plantea en este artículo es ¿Cuándo se ejecutan las actualizaciones en la tabla enlazada? Ya que cuando se declara una actualización no se ejecuta siempre que se produce un alta, baja o modificación en la tabla. La respuesta es que una actualización se ejecuta siempre que cambie alguno de los campos utilizados en las siguientes propiedades:

  • Caso A: Campo enlazado a la tabla en la que se produce la actualización.
  • Caso B: Campos utilizados en la condición del componente de actualización.
  • Caso C: Campos utilizados en la propiedad valor a actualizar.

Ejemplos

Ahora voy a poner un ejemplo de cada caso:

  • Ejemplo caso A. Si el campo enlazado donde se produce la actualización cambia de valor, entonces se lanza la actualización.
  • Ejemplo caso B: Si existe una condición que debe cumplirse para que se ejecute el componente de actualización, cualquier cambio de valor en alguno de los campos que intervengan en la fórmula producirá la evaluación de la condición y que se dispare la actualización.
  • Ejemplo caso C: Si en la fórmula del valor a actualizar, tanto por acumulación como por valor absoluto, se usan campos y alguno de ellos cambia de valor, el componente de actualización se dispara.

Como vemos hay una relación directa entre las variaciones de los valores de los campos que intervienen en estas tres propiedades. Por lo tanto, conociendo su funcionamiento podemos utilizar una astucia (recuerdos para Figueroa padrino de las astucias en Velneo) para forzar la ejecución de los componentes de actualización y usarlas en lugar de tener que crear tres eventos de tabla.

Supuesto

Supongamos que un campo de la tabla de artículos se calcula en base al valor que devuelve una función, lo que hace internamente esta función no tiene importancia en esta explicación. Supongamos que queremos que cada vez que se produce un alta, modificación o baja en la tabla histórica de referencias de un artículo se ejecute esta función y que se actualice el valor de un campo en la tabla de artículos. Podríamos plantear 3 posibles soluciones:

Soluciones

Solución A

  • Crear 3 eventos de tabla (interno o posterior a alta, baja y modificación).
  • En cada evento de tabla verificar si ha cambiado, por ejemplo, el campo referencia #REF. En caso afirmativo, se deberá cargar el registro del maestro para su modificación y ejecutar, por ejemplo, la función ART_ACT_REF(#ART) a la que le pasaremos el valor del campo artículo como parámetro. En caso de alta y baja se debería actualizar sobre el valor del campo artículo, sin embargo, en el caso de la baja habría que verificar si ha cambiado el artículo para lanzar el cálculo tanto para el artículo antigüo como para el nuevo, por lo que el código del evento de tabla se complica.

El handicap de esta solución es que hay que crear 3 eventos, además para no repetir código podría ser conveniente crear una función y lo más complicado es que en el evento de la modificación habría que controlar manualmente el cambio de artículo para deshacer con el viejo y rehacer con el nuevo.

 

Solución B

  • Crear una actualización a la tabla artículos desde la tabla referencias.
  • No ponemos nada en la condición para modificar del componente.
  • En la propiedad fórmula, llamamos a la función ART_ACT_REF_DSC(#ART, #REF), como vemos pasándole 2 parámetros. En realidad el parámetro #REF no se usa en la función, pero al estar presentes en la fórmula forzamos a que se evalúe y si cambia el valor de ese campo se fuerza la ejecución del componente de actualización.

El handicap de esta opción es que obliga a crear parámetros adicionales en la función cuando realmente no son necesarios.

 

 

Solución C (variación alternativa a la solución B)

  • Crear una actualización a la tabla artículos desde la tabla referencias.
  • En la condición para modificar del componente ponemos #REF=#REF. Como se puede observar la condición se cumple siempre por lo que no afecta a la ejecución de la actualización, la ventaja es que con esa fórmula estamos forzando que la actualización se ejecute si cambia la referencia del registro histórico del artículo.
  • En la propiedad fórmula, valor a ejecutar ejecutamos la función ART_ACT_REF_DSC(#ART) pasándole el artículo.

Esta es la opción que a priori deja el código de nuestra aplicación más sencillo de interpretar. Sería conveniente que en la propiedad comentario se podría especificar el motivo de incluir esa condición para modificar en el componente.

Con esta simple astucia nos ahorramos la creación de 3 eventos de tabla y el control manual del cambio del artículo lo que facilita en gran medida la programación además de convertirse en una alternativa de ejecución más óptima.

Correcciones en Velneo V7

Buenos días a todos y perdonad por tener un poco desatendido el blog pero he andado bastante liado.

Ayer Velneo presento una pequeña actualización para la versión V7.4 en la cual corrigen una serie de fallos.

El link a la noticia es este.

Lo bueno es que esta actualización a diferencia del resto es que no necesitamos aplicarla a priori para poder seguir trabajando ya que la versión 7.4 y 7.4.1 son compatibles entre si.

Pero claro esta, si no actualizas no obtendrás las mejoras. Esto es claro.

Una cuestión a tener en cuenta es:

-¿Es una revisión, una versión,  etc.?
Creo que este post en el foro puede ayudarte.

Y si nos pasamos por el foro encontraremos muchas mas de las características que esta versión nos ofrece.

Recordad que todo en el software avanza y Velneo mas ;)

Animo a todos y nos veremos pronto.