Varias personas me ha pedido en diversas ocasiones que les explique como crear una tabla con contadores desde SQL.
Supongamos que tenemos una tabla que va a tener estos tres contadores en una única fila Pedido, Albaran y Factura.
Creamos la tabla:
CREATE TABLE contadores (
pedido INT NOT NULL,
albaran INT NOT NULL,
factura INT NOT NULL )
Inicializamos los contadores (se toma cero para los valores iniciales):
INSERT INTO contadores VALUES ( 0, 0, 0 )
Obtener, por ejemplo, el valor del siguiente albarán:
1.- Bloqueamos la tabla para evitar que otro usuario acceda a la vez.
LOCK TABLES contadores WRITE
2.- Aumentamos el valor de albarán.
UPDATE contadores SET albaran = albaran + 1
3.- Obtenemos el nuevo valor.
SELECT albaran FROM contadores
4.- Quitamos el bloqueo.
UNLOCK TABLES
Hasta aqui la teoria, veamos ahora como se hace esto con Eagle 1 y MySQL:
(Usando funciones wrapeadas del cliente MySQL de la version 2.5 de Eagle 1)
// hCon contiene el handler de la conexion
// hRes contiene el handler de la consulta
// nAlbara recogera el valor del albaran correspondiente.
IF MSQuery( hCon, "LOCK TABLES contadores WRITE" )
...IF MSQuery( hCon, "UPDATE contadores SET albaran = albaran + 1" )
......IF MSQuery( hCon, "SELECT albaran FROM contadores" )
.........hRes := MSStoreResult( hCon )
.........nAlbaran := Val( MyReadRow( hRes )[1] )
.........MSQuery( "UNLOCK TABLES" )
......ELSE
.........Alert( MSError( hCon ) )
......END IF
...ELSE
......Alert( MSError( hCon ) )
...END IF
ELSE
...Alert( MSError( hCon ) )
END IF
De la misma forma se averiguaria el valor de cualquiera de los otros contadores.
Actualización:
Una pequeña optimización (si se me permite) sin tener que bloquear la tabla en MYSQL
UPDATE contadores SET albaran = LAST_INSERT_ID(albaran + 1)
SELECT LAST_INSERT_ID()
Para PostgreSQL y otras bases de datos utilizo secuencias que están hechas a propósito para este tema.
Comentado por Jorge perez a Miércoles, 14 de Septiembre de 2005Jorge,
Eso funciona en el caso de que la columna sea autoincremental.
En este caso es una tabla con varias columnas y una unica fila que contiene los contadores de pedidos, albaranes y facturas.
Saludos,
Hola Jose. No es necesario que la columna sea autoincremental. Es lo que yo uso para implementar contadores en MySQL y funciona perfectamente.
Comentado por Jorge perez a Miércoles, 14 de Septiembre de 2005Jorge,
Funciona con esta corrección:
UPDATE contadores SET albaran = LAST_INSERT_ID(albaran + 1);
SELECT LAST_INSERT_ID(albaran) FROM contadores;
Gracias por el apunte.
Aunque es lo mismo que hacer:
UPDATE contadores SET albaran = albaran + 1;
SELECT albaran FROM contadores;
Por lo que es necesario bloquear la tabla para que no se desvirtúe el valor en caso de que entre un UPDATE desde otro usuario.
Supongo que con el LAST_INSERT_ID() ocurrira lo mismo, es decir, que sea necesario bloquear.
Saludos,
Jose. Debe funcionar tal y como lo he descrito en mi post previo. Eso sí en un MySQL 4.1.
Adjunto está el enlace de la documentación de MYSQL que explica el truquito. En inglés claro.
http://dev.mysql.com/doc/mysql/en/innodb-locking-reads.html
Comentado por Jorge perez a Miércoles, 14 de Septiembre de 2005Jorge,
No va ni en la 4.0.17 ni en lqa 4.0.23.
Voy a actualizar el servidor y a probar.
Comentado por Jose A. Suárez a Miércoles, 14 de Septiembre de 2005