Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Conexión con bases de datos (https://www.clubdelphi.com/foros/forumdisplay.php?f=2)
-   -   Problema con Nº de pedidos SQL server ADO. (https://www.clubdelphi.com/foros/showthread.php?t=65889)

HccSoft 20-01-2010 10:58:08

Problema con Nº de pedidos SQL server ADO.
 
Estoy trabajando con una base de datos remota a la que acceden múltiples usuarios de varios países.

Para controlar la numeración utilizaba un campo integer que iba incrementando manualmente por años para luego crear un string más complejo del estilo 2010-PV000001.

Cuando el usuario desea crear un nuevo pedido el programa (no la base de datos) obtiene el último número integer, le suma uno y lo inserta en el nuevo registro dejando el resto en blanco.

Todo iba bien con la red interna hasta que este enero el número de usuarios empezó a incrementarse y se añadieron nuevos accesos internacionales con diferentes velocidades de ADLS. La semana pasada aleatoriamente se empezaron a repetir número de pedidos, no masivamente pero sí varios una o dos veces por semana. Visto esto estoy seguro que el problema irá en aumento y por eso os pido consejo.

¿Cómo lo solucionaríais?
¿Procedimiento almacenado?, bloqueo?

Gracias

Neftali [Germán.Estévez] 20-01-2010 11:44:34

¿Porqué no utilizas un campo Identity y le dejas ese trabajo al servidor?

A partir del Identity tú puedes componer el otro campo como te interese.

HccSoft 20-01-2010 14:40:32

Cita:

Empezado por Neftali (Mensaje 351221)
¿Porqué no utilizas un campo Identity y le dejas ese trabajo al servidor?

A partir del Identity tú puedes componer el otro campo como te interese.

No lo utilizo porque cada año la numeración se ha de reiniciar a cero. Tendría que modificar cada 1 de enero el código y restar el incremento del campo identidad.

marcoszorrilla 20-01-2010 14:47:31

Porque no le das un número de pedido provisional a cada usuario y solamente cuando graben el pedido le das el número real.

Aparte de esto si el número de Pedido fuera PK evitarías la repetición.

Un Saludo.

HccSoft 20-01-2010 15:05:30

Cita:

Empezado por marcoszorrilla (Mensaje 351233)
Porque no le das un número de pedido provisional a cada usuario y solamente cuando graben el pedido le das el número real.

Aparte de esto si el número de Pedido fuera PK evitarías la repetición.

Un Saludo.

Tendría el mismo problema que ahora. El problema es que entre el SELECT que busca el número mayor de ese campo y el insert alguien ha ejecutado esa misma consulta teniendo ambos usuarios el mismo número. Para que pase ha de dar la casualidad que los dos usuarios creen un nuevo registro a la vez. No ocurre casi nunca pero es algo que no me puedo permitir que falle.

Entre el SELECT y el INSERT pueden pasar milisegundos pero ya es suficiente como para encontrar registros con el mismo número.

Si invierto el proceso tendría el mismo problema a la hora de guardar y crear el nuevo número. Si dos usuarios guardaran a la vez, ambos acabarían con el mismo número como ahora.

Neftali [Germán.Estévez] 20-01-2010 15:38:54

Cita:

Empezado por HccSoft (Mensaje 351235)
Entre el SELECT y el INSERT pueden pasar milisegundos pero ya es suficiente como para encontrar registros con el mismo número.

En ese caso sólo se me ocurre que utilices transacciones y bloquees al resto de usuarios para esa operación.

A la hora de hacer el INSERT del registro, debes hacer el SELECT y el INSERT del contador, todo ello dentro de la misma transacción, de forma que se el INSERT del registro falla (por lo que sea) tampoco se actualice el contador.
Además, utilizando los diferentes tipos de ISOLATION (para la transacción) creo que puedes llegar a bloquear las lecturas del resto de usuarios para que no obtengan el mismo contador.

Si estás accediendo con ADO, en la conexión y en las consultas también puedes modificar esta característica.

HccSoft 20-01-2010 16:42:09

Cita:

Empezado por Neftali (Mensaje 351240)
En ese caso sólo se me ocurre que utilices transacciones y bloquees al resto de usuarios para esa operación.

A la hora de hacer el INSERT del registro, debes hacer el SELECT y el INSERT del contador, todo ello dentro de la misma transacción, de forma que se el INSERT del registro falla (por lo que sea) tampoco se actualice el contador.
Además, utilizando los diferentes tipos de ISOLATION (para la transacción) creo que puedes llegar a bloquear las lecturas del resto de usuarios para que no obtengan el mismo contador.

Si estás accediendo con ADO, en la conexión y en las consultas también puedes modificar esta característica.

Sí, es la solución que había pensado.

Por si a alguien le interesa la pongo aquí :

Código:

DECLARE @numero int

BEGIN TRAN
      SELECT @numero = max(N_PRESUPUESTO) FROM PEDIDOS WHERE fecha > '01/01/2010'

      INSERT INTO PEDIDOS (N_PRESUPUESTO) values (@numero+1)

COMMIT TRAN

select @@identity as pedido

Todo dentro de un ADOQUERY que retorna la identidad del nuevo registro.

Cañones 20-01-2010 22:30:03

Cita:

Empezado por Neftali (Mensaje 351240)
En ese caso sólo se me ocurre que utilices transacciones y bloquees al resto de usuarios para esa operación.

A la hora de hacer el INSERT del registro, debes hacer el SELECT y el INSERT del contador, todo ello dentro de la misma transacción, de forma que se el INSERT del registro falla (por lo que sea) tampoco se actualice el contador.
Además, utilizando los diferentes tipos de ISOLATION (para la transacción) creo que puedes llegar a bloquear las lecturas del resto de usuarios para que no obtengan el mismo contador.

Si estás accediendo con ADO, en la conexión y en las consultas también puedes modificar esta característica.

No conosco SQL Server pero la teoría es la misma para todas las DD.BB y es la que te acaba de explicar Neftali. Por lo menos a mi me funciona.

Saludos.

marcoszorrilla 21-01-2010 06:45:37

Cita:

Empezado por HccSoft (Mensaje 351235)
Tendría el mismo problema que ahora. El problema es que entre el SELECT que busca el número mayor de ese campo y el insert alguien ha ejecutado esa misma consulta teniendo ambos usuarios el mismo número. Para que pase ha de dar la casualidad que los dos usuarios creen un nuevo registro a la vez. No ocurre casi nunca pero es algo que no me puedo permitir que falle.

Entre el SELECT y el INSERT pueden pasar milisegundos pero ya es suficiente como para encontrar registros con el mismo número.

Si invierto el proceso tendría el mismo problema a la hora de guardar y crear el nuevo número. Si dos usuarios guardaran a la vez, ambos acabarían con el mismo número como ahora.

La forma de hacer lo que digo es con una tabla que guarda un contador y que se bloquea en el momento de grabar el número incrementado.

Un Saludo.

HccSoft 21-01-2010 12:21:36

Cita:

Empezado por marcoszorrilla (Mensaje 351360)
La forma de hacer lo que digo es con una tabla que guarda un contador y que se bloquea en el momento de grabar el número incrementado.

Un Saludo.

Al final he agrupado todo en una misma transacción. El SELECT para buscar el número, un INSERT y finalmente otro SELECT con el índide identidad para poder acceder al nuevo registro.

De todas formas me interesaría saber como se puede bloquear el acceso a una tabla mientras realizas alguna operación. Nunca va mal tener varias soluciones para estos problemas.

Gracias a todos

marcoszorrilla 21-01-2010 14:22:17

Obviamente el bloqueo de un registro varía de unos motores a otros por lo que la mejor solución es consultar la ayuda para el tipo de tablas-componentes-motor utilizado.

Un Saludo.


La franja horaria es GMT +2. Ahora son las 22:36:57.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi