jueves, 16 de junio de 2011

Manejo eficiente de Consecutivos y Correlativos 1

El manejo de Consecutivos, correlativos, secuenciales, números de serie(o como usted los desee llamar) es un inconveniente al que se enfrentan muchos desarrolladores analizando la web(foros y blogs).
En este artículo explicaré de una forma detallada con una solución(proyecto) en Windows Forms, Visual Basic.Net y Sql Server 2005 Express-aplicable también para la web- una de las formas en que los podemos manejar eficientemente y no morir en el intento.

Antes debemos definir de una forma clara el término, en mi caso lo llamaré "Consecutivo".

Consecutivo: Es un número que se genera de forma secuencial en un documento(entiendase por documento una Factura, Compra, Pedido) y que normalmente es la Clave de la tabla del documento y que lo identifica de forma única de los otros que se creen.

Ejemplos
Facturas.

Numero Factura
0001
0002
0003

Hasta el momento no vemos ningún problema, entonces ¿cuales son los inconvenientes que se nos presentan?

Voy a mencionar algunos con interrogantes:
¿Debería utilizar Campos Identidad(autoincrementales)?
¿Es tarea de la base de datos o del sistema?
¿Qué pasa si el numero debe tener prefijos ejemplo: A0001 o sufijos ejemplo:0001A?
¿Cómo generarlos?
¿Como manejar la concurrencia?


Voy a responder estas preguntas de forma corta y no dogmática desde mi perspectiva y algo de experiencia como desarrollador.

- ¿Debería utilizar Campos Identidad(autoincrementales)?
Los campos autoincrementales son campos de tipo entero que los maneja la base de datos, es decir, cada vez que se crea una nueva fila la base de datos se encarga de generar un numero consecutivo a este campo, por defecto comienza desde 1 y asi sucesivamente sumandole uno cada vez(a no ser que hayamos definido que el incremento sea de otra cantidad como de 2).Es el método mas rápido de manejar consecutivos.
Personalmente no aconsejo utilizar campos autoincrementales en los consecutivos, es una forma poco eficiente de manejarlos.
¿Por qué? Por varias razones.
Mira algunas:
No tienes control sobre ellos. Los campos autoincrementales como su nombre lo dice se encarga de manejarlos o incrementarlos la base de datos. Algo que no es muy bueno. No es bueno porque por un lado el tipo de valor es integer. Alli pierdes la oportunidad de manejar el consecutivo con sufijos y prefijos, algo que es muy utilizado por muchas empresas. Los prefijos y sufijos son caracteres que se agregan antes o despues de la numeración para identificar de una forma clara el consecutivo.
Algunas empresas cuando facturan lo hacen desde diferentes puntos de venta. Desean saber con el consecutivo desde que punto de venta se generó la factura, al utilizarlo sufijos o prefijos se soluciona este problema. Si tengo dos puntos de venta llamados A y B. Simplemente puedo agregar un prefijo a la numeración. En este Caso
Empresa A asi:A0001 Empresa B asi:B0001.
Para manejar el consecutivo de esa forma y tenerlo en un solo campo necesitas un campo de tipo string en la base de datos y los autoincrementales son integer(enteros). Asi que no puedes manipularlo o si cambiaras el rango de numeración no podrías cambiarlos desde la aplicación.
Los consecutivos se pierden cuando falla una transacción.
Supongamos que vas a crear una Factura cuyo número en el autoincremntal debería ser el numero 2, cuando intentas guardar la factura se produce un error en el sistema y la transacción( la cual hace que un conjunto de setencias sql se ejecute en un bloque, si el bloque no se ejecuta completo se cancela todo) falla.
En sql server 2005 ese número consecutivo(el numero 2) se pierde y si guardas una factura aparecera el número 3. Este problema es algo muy grave en aplicaciones empresariales monitoreadas por las leyes gubernamentales. No se les permite que desaparezca ningún consecutivo "magicamente" de la numeración. Por un sistema que funcione asi puede ser penalizada y multada la empresa(eso ocurre en mi país). Los consecutivos nunca se deben perder.
Para controlar un poco el problema tendrías que validar todos los datos fuera de la transacción, aun asi sigues corriendo el riesgo de que algo inesperado ocurra y se cancela la transacción con la consecuencia de perder el consecutivo.

¿Es tarea de la base de datos o del sistema?
Por lo anterior deducimos de que es una tarea conjunta. En la base de datos almacenarías tu información para manejar los consecutivos, pero con la programación desde tu sistema la controlarías.

¿Qué pasa si el numero debe tener prefijos ejemplo: A0001 o sufijos ejemplo:0001A?
En este caso se debe crear un sistema de consecutivos flexible que permita manejar esto. Próximamente veremos un proyecto completo. Pero el sistema debe permitir establecer prefijos y sufijos si lo deseamos, un rango de numeración: de donde hasta donde y cambiar el consecutivo que sigue dentro del rango.

¿Cómo generarlos?

La mejor forma de generarlos es guardar toda la configuración del consecutivo en la base de datos y luego consultar esos datos y manipularlos(concatenarlos, sumarlos y formatearlos) en el momento que se asigna el consecutivo al documento.

¿Como manejar la concurrencia?
La concurrencia es cuando dos terminales de aplicación acceden al mismo tiempo a la base de datos y solicitan un numero de consecutivo, debe garantizarse que el número que pida de consecutivo no sea igual para las dos, pues se generaría el mismo número de factura. Como los datos de el consecutivo estaran en la base de datos, estará guardado un campo que indica cual es el número que sigue en la numeración. Este campo se debe bloquear cuando sea consultado por una de las terminales y liberado cuando se termine el proceso de la transacción donde se guarda el documento, en este caso una Factura. Existe algunos formas de bloqueo aplicables al proyecto.

En la siguiente entrega veremos la explicación del proyecto.

11 comentarios:

  1. Muy interesante el articulo compañero...

    ResponderEliminar
  2. Muy bueno, para cuando estarà lista la otra parte?

    ResponderEliminar
  3. Hola José. Gracias por leer el articulo.Lo más pronto posible subiré y explicaré este sencillo ejemplo, espero desocuparme pronto. Saludos.

    ResponderEliminar
  4. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  5. habrá alguna posibilidad de que puedas terminar la serie de artículos? Es justo lo que ando buscando y quisiera tener una ayuda con los problemas que estoy enfrentando en este momento.
    Muchas gracias.

    ResponderEliminar
  6. Estimado has podido subir el ejemplo?? podrias pasar el link??

    ResponderEliminar
  7. Han Pasado ya 4 Años y NO he visto la segunda parte del articulo pero a pesar del tiempo queria saber si el admin ya tiene preparada la segunda parte del articulo gracias y muy buen tema

    ResponderEliminar
  8. See Yo También Necesito el Ejemplo de Codigo Completo

    ResponderEliminar
  9. Espero les sirva:

    BEGIN TRANSACTION

    select @v_nu_fila = max(convert(int, nu_fila)) from TABLA WITH(UPDLOCK, HOLDLOCK);
    if (@v_nu_fila is null) Set @v_nu_fila = 0;
    set @v_nu_fila = convert(int, @v_nu_fila) + 1;

    insert into TABLA (nu_correlativo, ....)
    values (@v_nu_fila, ....)

    COMMIT TRANSACTION

    ResponderEliminar