PDA

Ver la Versión Completa : Corregir un generador


sur-se
24-07-2003, 11:50:09
Hola, estoy utilizando un generador como parte de la clave primaria de una tabla y me funciona bien.

El problema es que si se borra un registro y este es el último, me gustaría poder corregir el generador para que en el siguiente nuevo le asigne el mismo número (es decir no se pierda el número de secuencia). Vale, esto es fácil de hacer, basta con poner el generador al número correcto y ya está.

Sin embargo, la cosa no es tan simple cuando estamos en un entorno multiusuario, ya que mientras comparo el valor actual del generador con el número del registro que borro, es posible que otro usuario haga una solicitud de valor del generador, y entonces el resultado final quedaría erróneo. He pensado en realizar la comprobación en el evento after delete, y si el registro que se borró es el último, que sea ahí donde se ajuste el contador, pero no estoy seguro de que ocurriría si diese la casualidad de que durante la ejecucición de ese trigger, otro usuario solicitase un número. Las posibilidades de que sea en el mismo momento son pocos, pero la ley de murphy seguro que se aplica. ¿Que me podéis sugerir?

Salu2.

kinobi
24-07-2003, 13:00:23
Hola,

Posteado originalmente por sur-se
¿Que me podéis sugerir?

sinceramente, poca cosa utilizando generadores. Los generadores pueden asegurar valores únicos, pero no hay forma de garantizar (en todos los casos) una secuencia (ascendente o descendente) sin huecos. Al estar fuera del control transaccional es simplemente imposible.

Una alternativa es olvidarse de los generadores y crear un recurso propio dentro de la base de datos (por ejemplo una tabla de contadores) para asignar los valores en secuencia. Es importante asegurar que cada vez que se utiliza la tabla de contadores, se haga de forma exclusiva (para escritura, ya que para lectura no es posible) , mediante el bloqueo del contador en cuestión y gestionar la posible duplicación de valores (índices únicos, claves primarias, triggers, ...).

Saludos.

sur-se
24-07-2003, 13:29:23
Gracias por la respuesta.

Estoy de acuerdo contigo en lo que comentas, pero me parecen más las ventajas de usar un generador frente a tener que desarrollar un contador con sus bloqueos, y por eso me decidí a usarlos a pesar de todo.

¿Y lo que comentaba de hacerlo en el trigger del evento after delete?. Creo que no se puede garantizar que el trigger se ejecute completamente sin que otra instrucción sql se cuele por medio de la ejecución, ¿o sí?

Salu2.:confused:

kinobi
24-07-2003, 13:35:17
Posteado originalmente por sur-se
¿Y lo que comentaba de hacerlo en el trigger del evento after delete?.

es indiferente. Al no estar bajo el control de ninguna transacción, el generador no se ve afectado ni por el aislamiento entre transacciones, ni por commits y rollbacks, ni por los bloqueos de escritura. En cuanto una transacción (o varias) tocan su valor (a través de la función incorporada GENID) no hay posibilidad de controlar la secuencia.

En resumen, fueron diseñados con la idea de proporcionar un mecanismo que asegurara valores únicos, pero no para garantizar la secuencia (sin huecos).

Saludos.

JamesCole
25-07-2003, 02:15:56
Yo te sugiero lo tener la siguiente estructura :

una tabla de FACTURAS (por ejemplo) con los campos :

FACTURA INTEGER NOT NULL
NUMFACTURA INTEGER NOT NULL

Creas la clave primaria usando el fichero FACTURA
Define un UNIQUE para el Campo NUMFACTURA

Creas dos generadores uno cada para campo

El generador del campo FACTURA lo usas desde la aplicacion, para asignarle un valor.

Pero el generador para NUMFACTURA usalo en el Trigger de la tabla BEFOREINSERT y ahi le introduces el NUMFACTURA.

Y justamente es ahi donde podrias comprobar si hay huecos o asignarle un valor nuevo desde el generador. De esa manera te aseguras que no habra huecos entre registros y los huecos que habra solo sera a nivel del campo usado como clave primaria.

Yo en caso de mantenimentos de FACTURAS con cabecera y detalle lo que hago es generar el campo NUMFACTURA en el Trigger BEFOREUPDATE atraves de un campo de control (Booleano) para indicar cuando quiero que realmente me genere el numero de factura (NUMFACTURA).

De esta manera puedo grabar la cabecera para introducir lineas de detalle, sin problemas de FOREIGNKEY's y cuando finalmente el usuario da por hecha la factura (BOTON OK,je je ), justamente es ese momento cuando se genera el NUMFACTURA.

En un sistema multiusuario me asegura la continuidad de numeracion y no se perderan numeraciones si un usuario cancela (BOTON CANCEL, jeje) despues de haber tenido que grabar la cabecera y algunas lineas en el proceso de "añadir una factura nueva".


Vaya rollo solte!!!! jejejeje

No se hasta me ha parecido bonito asi tan bien explicado, espero que parezca bonito e interesante, sino puee naa!! :)

Espero que te sirva y saludos a todos !!!!!!

kinobi
25-07-2003, 08:56:30
Hola,

Posteado originalmente por JamesCole
Y justamente es ahi donde podrias comprobar si hay huecos o asignarle un valor nuevo desde el generador. De esa manera te aseguras que no habra huecos entre registros y los huecos que habra solo sera a nivel del campo usado como clave primaria.

no acabo de comprender la necesidad de disponer de dos generadores y dos claves (una primaria y otra alternativa), si al final es necesario hacer un proceso "manual" de verificación de huecos en una, al menos, de las secuencias.

Como hemos comentado en el hilo, basar una secuencia sin huecos en el uso de generadores es imposible en un entorno multi-transaccional como InterBase, a no ser que se recurra a procesos auxiliares (externos a los propios generadores); de ahí que no comprenda cuál es la mejora de añadir un segundo generador.

Saludos.

nachoasensio
25-07-2003, 09:23:04
Hola:

Es posible que lo que os diga sea una tontería, pero yo el sistema que explico a mis alumnos para conseguir secuencias de números de facturas sin huecos es, sencillamente, no llamar al generador hasta que toda la información está disponible (cabecera y líneas de la factura) y se haya confirmado la ejecución de la factura. Una vez que ese proceso se ha realizado, no se puede eliminar esa factura; si se desea eliminar del sistema habrá que insertar una factura de abono (idéntica a la realizada pero con las cantidades negativas).

El único problema que puede presentar es un fallo en la BD tras haber creado la cabecera de la factura y no haber metido todavía las líneas, ya que habría que hacer un rollback (y el generador no se entera). Para ello, si se produce ese fallo, como el nº de la factura ya está reservado, se reintenta la inserción de cabecera y líneas sin llamar al generador, usando ese número.

Hasta donde lo he probado, funciona perfectamente en entornos multiusuario. Si alguien cree que puede fallar le agradecería que lo comentara en este foro

Un saludo

Nacho

kinobi
25-07-2003, 09:37:30
Hola,

Posteado originalmente por nachoasensio
El único problema que puede presentar es un fallo en la BD tras haber creado la cabecera de la factura y no haber metido todavía las líneas, ya que habría que hacer un rollback (y el generador no se entera). Para ello, si se produce ese fallo, como el nº de la factura ya está reservado, se reintenta la inserción de cabecera y líneas sin llamar al generador, usando ese número.

estoy de acuerdo. Nótese que en mis anteriores mensajes no digo que no pueda conseguirse una secuencia sin huecos para asignar a una clave, lo que pretendo decir es que, en InterBase, no es posible garantizarlo con el uso exclusivo de generadores y sin procesos auxiliares, como tú mismo apuntas al decir que se "se reintenta la inserción" si surge algún problema y al utilizar artificios como las facturas de abono.

Saludos.

sur-se
25-07-2003, 13:03:01
Hola,
está claro que no se puede mantener una secuencia sin huecos, ya que en el momento en el que el usuario borre un registro antiguo, ya quedará el hueco. Yo no pretendo que el programa busque el hueco y el próximo registro que se inserte, lo haga usando ese hueco.
Me quería centrar en un problema concreto, que es el borrado del último registro que añadí, es decir, ya tengo el número de la secuencia y el registro se añadió, pero ahora lo borro. Me gustaría ajustar la secuencia, pero claro, en ese momento puede otro usuario pedir un número y ahí está el problema.

No tiene solución sin poder bloquear el generador mientras se actualiza. Como esto no se puede hacer, pues tendré que meter código o bien ignorar el problema y que no se ajuste (esto es lo mejor, lo más sencillo, lo más rápido, pero no le gusta a mi jefe :D )

Salu2.

__cadetill
26-07-2003, 12:32:18
Posteado originalmente por kinobi
como tú mismo apuntas al decir que se "se reintenta la inserción" si surge algún problema y al utilizar artificios como las facturas de abono.


Hola kinobi. No se a que te referiras por artificios, pero yo creo que en temas de facturas, albaranes, pedidos, numeros de tickets,.... es la forma normal (y correcta) de actuar. :rolleyes:

Posteado originalmente por sur-se

Me quería centrar en un problema concreto, que es el borrado del último registro que añadí, es decir, ya tengo el número de la secuencia y el registro se añadió, pero ahora lo borro. Me gustaría ajustar la secuencia, pero claro, en ese momento puede otro usuario pedir un número y ahí está el problema


Bueno, esto quizas lo puedas solucionar utilizando una sentencia SQL con un

select max(campo) + 1 from tabla

y calcularlo siempre en el BeforePost de la tabla mirando que sea una insercion (o bien por medio de un trigger)

kinobi
27-07-2003, 17:46:56
Hola Cadetill,

Posteado originalmente por cadetill
Hola kinobi. No se a que te referiras por artificios, pero yo creo que en temas de facturas, albaranes, pedidos, numeros de tickets,.... es la forma normal (y correcta) de actuar. :rolleyes:

yo no discuto que sea la forma normal (y correcta) de actuar. Simplemente afirmo que el crear facturas de "abono" (tal como se han definido) con "cantidades negativas" es un artificio para evitar la eliminación (por la razón que sea) de facturas y que la contabilidad quede cuadrada, además de conseguir una numeración correlativa (y sin huecos) en la secuencia.

Y es un artificio porque es artificial crear una factura con importes (o cantidades) negativas. Nadie vende -1000 Kilos de manzanas, ni tampoco vende 1 Kilo de manzanas a -2 Euros.

Que sea un artificio no significa que no pueda ser habitual y también correcto.

Saludos.

marcoszorrilla
27-07-2003, 18:35:07
También hay que tener en cuenta, que una factura de abono no es necesario que contenga nombres de productos.

Puede ser un Abono de X euros, por el motivo que sea, un descuento que se omitio en la factura anterior, algún producto defectuoso y otros muchos motivos por los que se acuerda el abono.

Un truco suele ser dar de alta un Producto llamado Abono-Euros y otro Abono-Centimos, para hacer un abono de 112,39 € le ponemos -112 del primero y -39 del segundo.

Por otra parte el abono no tiene por que ser negativo, si lo será la anotación contable. que disminuirá el debe de la cuenta del Cliente (430) y por lo tanto quedará la deuda enjugada en el próximo cobro.

A mi juicio si se hace una factura negativa suele ser por devolución del producto completo, para así volver a actualizar el almacén, es decir devolver los productos al fichero de Almacén.

Aunque contablemente las devoluciones irían a la cuenta(608).

Un Saludo a todos.

kinobi
27-07-2003, 18:41:45
Hola,

Posteado originalmente por marcoszorrilla
Puede ser un Abono de X euros, por el motivo que sea, un descuento que se omitio en la factura anterior, algún producto defectuoso y otros muchos motivos por los que se acuerda el abono.

sí, estoy de acuerdo. Insisto que cuando me refería a artificio lo hacía dentro del contexto en el que ha aparecido dentro del hilo: para evitar tener que eliminar facturas y que se descuadre la secuencia, no por un requisito del sistema: una devolución, una factura con importes incorrectos.

Saludos.

marcoszorrilla
27-07-2003, 18:47:32
Totalmente de acuerdo, pero además añado otro asunto importante, podemos hallarnos en un trimestre distinto al que se produjo el error y entoncés ya habremos hecho el ingreso de IVA correspondiente.

Con esto la cuenta 475 que habríamos dejado cuadrada en su momento por las diferencias entre 477 y 472, quedaria descuadrada.


Un Saludo.

__cadetill
27-07-2003, 19:03:50
pos nada, solo disculparme por el pequeño mal entendido de las palabras de kinobi :o

Creo que ha quedado bastante claro el tema :D