Obtener campos Auto-Incrementales y generarlos (Consulta)

407 views
Skip to first unread message

Diego Dagostino

unread,
Jul 28, 2016, 11:44:43 PM7/28/16
to Comunidad de Visual Foxpro en Español
Antes que nada gracias por su ayuda.

Espero que me puedan dar una mano, ya que no conozco mucho sobre VFP.
La razón por la que escribo es para consultar sobre dos dudas que tengo:

1) ¿Como se recupera el valor auto-incremenal de una columna una vez insertado? 
La tabla es cuestión tiene una columna código, la cual es de tipo entero y auto-incremental, fue creada con VFP9. 
Genero el insert, todo correcto, se genera automáticamente el nuevo código, pero desconozco como recuperarlo. Estoy buscando algo así como el scope_identity o @@identity de SQL server.
Una solución es hacer MAX de "campo" con un select, pero nada me garantiza que dado la concurrencia no este leyendo otro insert mas nuevo, que el que acabo de ejecutar contra la tabla.

2) En las bases que fueron creadas con VFP6, como se genera el campo incremental, se que en esta versión no se encuentra soportado dicha característica. 
Por lo que puede averiguar es algo como "SELECT NVL(MAX(Campo), 0) + 1 FROM Tabla" el problema sigue siendo la concurrencia, entre que calculo el próximo valor y lo inserto.

Como información adicional, estas bases las consumo desde una web con C#, por lo que a los DBF estoy accediendo mediante OLE DB (Son tablas DBF sueltas no tiene DBC).
Tengo acceso al SQL y a algunas de las funciones propias de Fox.

En el caso puntual del segundo punto, intente usar LOCK y FLOCK que están soportadas por OLE DB, pero siempre me devuelve falso y no logro generar el bloqueo a la tabla (Soy el único que la esta usando y no esta bloqueada por otra aplicación/usuario).

Como no tengo experiencia manejando este tipo de base de datos, desconozco estos temas por lo que consulto con ustedes que de seguro están mas cancheros que yo.
Muchas gracias por su tiempo y ayuda.


Carlos Miguel FARIAS

unread,
Jul 29, 2016, 7:20:38 AM7/29/16
to Grupo Fox
Después de insertar un registro en una tabla o cursor, el puntero de registro de la tabla destino queda posicionado sobre ese registro por lo que 

INSERT INTO tuTabla (bla bla...

nUltimo = tuTabla.campoautoincremental

fijate en la ayuda de VFP 9, en la parte de "Remarks" 4° párrafo.

Saludos: Miguel, La Pampa (RA)

Larga Vida y Prosperidad
Que la Fuerza los acompañe

Diego Dagostino

unread,
Jul 29, 2016, 11:52:11 AM7/29/16
to publice...@googlegroups.com
Gracias por tu repuesta. 
El problema que yo no puedo escribir codigo VFP, por que me conecto mediante OLE DB. 
Salvo que haya una función que lo haga.
Solo le mando el insert a través de una conexion OLE DB. 

arquinav

unread,
Jul 29, 2016, 12:42:12 PM7/29/16
to Comunidad de Visual Foxpro en Español
consulta la funcion GETAUTOINCVALUE()

Víctor Hugo Espínola Domínguez

unread,
Jul 29, 2016, 12:50:20 PM7/29/16
to publice...@googlegroups.com
Puedes probar con SELECT MAX(campoAI) FROM tabla WHERE campo1 = val1 AND campo2 LIKE val2 etc..., = para datos numéricos y LIKE para carácter

Saludos,
Víctor.
Lambaré - Paraguay.

Carlos Miguel FARIAS

unread,
Jul 29, 2016, 1:40:44 PM7/29/16
to Grupo Fox

El select max() no sirve en un entorno de alta concurrencia porque puede devolver el id de una transacción de otro usuario.
Si son tablas nativas, por que usas oledb?
Debe haber alguna función que devuelva esa clave.
No tengo aquí en la tablet para consultar.
Saludos: Miguel, La Pampa RA

Víctor Hugo Espínola Domínguez

unread,
Jul 29, 2016, 2:02:53 PM7/29/16
to publice...@googlegroups.com
Hago la suposición de que otro usuario no ingresará los mismos datos, por eso el WHERE.

Saludos,
Víctor.
Lambaré - Paraguay.


Diego Dagostino

unread,
Jul 29, 2016, 2:45:23 PM7/29/16
to publice...@googlegroups.com
Sos un grosoooooo, esta es la función que buscaba para los campos auto-incrementales: " GETAUTOINCVALUE()".
Me salvaste, por que en el MSDN de las fusionen soportadas por OLEDB no figuraba, pero funciona de 10. 
Me resolviste en un abrir y cerrar de ojo el primer punto.
Mil gracias te lo agradezco un montón. Genio

Diego Dagostino

unread,
Jul 29, 2016, 2:47:56 PM7/29/16
to publice...@googlegroups.com
Uso OLEDB por que es un sistema que lo estoy migrando a ASP.NET y SQL Server 2012.
El tema que ambos sistemas tienen que trabajar en paralelo hasta que logre migrar todo.
Por lo cual todos los módulos en común tengo que insertar en los DBF para que el sistema viejo siga viendo la info.
Una vez migrados los módulos los descontinuo.

Diego Dagostino

unread,
Jul 29, 2016, 3:27:42 PM7/29/16
to publice...@googlegroups.com
Ahora solo me queda averiguar como crear campos auto-incrementales para tablas DBF en VFP 6.
Con la siguiente consulta: SELECT NVL(MAX(Campo), 0) + 1 FROM Tabla y luego agregar el valor devuelto en el insert funciona.
Raramente no me deja incluirlo dentro del insert como INSER INTO Tabla (V1,V2,V3) VALUES ((SELECT NVL(MAX(Campo), 0) + 1 FROM Tabla), ?. ?).
Y la única manera de que no halla concurrencia que encontré fue abrir la tabla con mode=shared exclusive en la cadena de conexión. Como el modelo que uso es abrir conexión -> ejecutar consulta -> cerrar conexión. El bloqueo exclusivo dura lo que tarda en ejecutarse la consulta.

Carlos Miguel FARIAS

unread,
Jul 29, 2016, 6:47:22 PM7/29/16
to Grupo Fox

En tu consulta inicial indicaste que tenías alta concurrencia, por lo que el mecanismo de abrir exclusivo buscar mayor cerrar, puede ser lento o darte error de que no puede abrir exclusivamente.
Pero si es para un sistema migrando entiendo debe ser suficiente.


Saludos: Miguel, La Pampa RA

Diego Dagostino

unread,
Jul 30, 2016, 11:48:26 AM7/30/16
to publice...@googlegroups.com
Tras investigar un poco mas, descubrí que puedo ejecutar bastante código VFP como store procedure de un OLEDB en .NET.
Encontré mucho por la web ejemplos donde se calcula la secuencia del ID en una tabla externa con las columnas "nombre tabla" y "Proximo ID", lamentablemente no es mi caso y no puedo modificar la aplicación ya creada.
Por lo cual decidí generar el próximo código el cual esta funcionando, ustedes me dirán si esta bien:

LOCAL NEWID
            SET REPROCESS TO 30 SECONDS
            USE EMPRESA IN 0
            SELECT EMPRESA

            NEWID = -1
            IF FLOCK()
                CALC MAX(empcod) TO NEWID
                APPEND BLANK
                REPLACE empcod WITH NEWID + 1 IN EMPRESA
                NEWID = EMPRESA.empcod
                UNLOCK
            ENDIF
                RETURN NewID

La idea es generar un registro en blanco, para evitar el ingreso de los campos que aceptan null y generar en ese nuevo registro el valor de la clave primaria secuencial, luego lo devolver el ID generado para actualizo el resto de los campos. No hago el insert directo por que quiero hacerlo a través de .Net con parámetros por medio de OLEDB.

Las tablas DBF estan suletas y no existe un archivo DBC, por lo que creo que hay caracteristica que no funcionan, por ejemplo el FLOCK entra en el IF por lo cual se establece el bloqueo, pero si le saco el UNLOCK y ejecuto dos programas en paralelo el segundo no se queda esperando los supuestos 30 segundos que indique. ¿Esto se puede deber a la falta de un archivo DBC que gestiona los bloqueo?.
Lo comento por que lei que sin un archivo DBC no se puede hacer uso de transacciones, cosa que probe y tampoco funciona. No tira error, pero al hacer un rollback me guarda el valor de todas formas.
 

Diego Dagostino

unread,
Jul 30, 2016, 11:54:55 AM7/30/16
to publice...@googlegroups.com
Tras investigar un poco mas, descubrí que puedo ejecutar bastante código VFP si lo ejecuto como un store procedure en OLEDB NET.
Encontré mucho ejemplos, por la web, donde se calcula la secuencia del ID en una tabla externa con las columnas "nombre tabla" y "Proximo ID", lamentablemente no es mi caso y no puedo modificar la aplicación ya creada.
Por lo cual decidí generar el próximo código el cual esta funcionando, ustedes me dirán si esta bien:

LOCAL NEWID
            SET REPROCESS TO 30 SECONDS
            USE EMPRESA IN 0
            SELECT EMPRESA

            NEWID = -1
            IF FLOCK()
                CALC MAX(empcod) TO NEWID
                APPEND BLANK
                REPLACE empcod WITH NEWID + 1 IN EMPRESA
                NEWID = EMPRESA.empcod
                UNLOCK
            ENDIF
                RETURN NewID

La idea es generar un registro en blanco, para evitar el ingreso de los campos que no aceptan null y generar en ese nuevo registro el valor de la clave primaria secuencial. Luego al devolver el ID generado proceso a actualizar el resto de los campos. No hago el insert directo por que quiero hacerlo a través de .Net con parámetros por medio de OLEDB. Por lo que leí los insert en VFP ingresan los valores sin usar parametros "?".

Al margen de lo anteriror quiero comentar que las tablas DBF estan sueltas en una carpeta y no existe un archivo DBC que las gestione. Por lo que creo que hay características que no funcionan, por ejemplo la función FLOCK entra en el IF por lo cual se establece el bloqueo, pero si le saco el UNLOCK y ejecuto dos programas en paralelo el segundo no se queda esperando los supuestos 30 segundos que indique. ¿Esto se puede deber a la falta de un archivo DBC que gestiona los bloqueo?.
Lo comento por que leí que sin un archivo DBC no se puede hacer uso de transacciones, cosa que probé y efectivamente tampoco funciona. No tira error, pero al hacer un rollback me guarda el valor de todas formas como si hubiese confirmado la transacción.

El 29 de julio de 2016, 19:47, Carlos Miguel FARIAS <carlosmig...@gmail.com> escribió:

Diego Dagostino

unread,
Jul 30, 2016, 12:13:28 PM7/30/16
to publice...@googlegroups.com
Con el siguiente codigo logre hacer que bloquee, aunque no se por que, jajajaja disculpen me ingorancia, pero cero de FOX:

LOCAL NEWID, AGAIN
            SET REPROCESS TO 10 SECONDS
            USE EMPRESA SHARED
            
            AGAIN = .t. 
            NEWID = -1
            DO WHILE AGAIN
                IF FLOCK()
                    CALC MAX(EMPCOD) TO NEWID 
                    APPEND BLANK
                    REPLACE EMPCOD WITH NEWID + 1 IN EMPRESA
                    NEWID = EMPRESA.EMPCOD

                    AGAIN = .f.
                    UNLOCK
                ENDIF
            ENDDO

            SET REPROCESS TO 0
            RETURN NewID

Diego Dagostino

unread,
Jul 30, 2016, 3:49:31 PM7/30/16
to publice...@googlegroups.com
Alguien sabe como ejecutar el UNLOCK y END TRANSACTION o RALLBACK en caso de error. No entiendo como se tratan los errores en VFP 6.
No soy capas de generar el ROLLBACK en caso de error.
Nota. No puedo usar TRY - CATCH, me dice función no soportada, por la versión de foxpro que fue creada la tabla.


            LOCAL NEWID, ISLOCK
            SET REPROCESS TO 10 SECONDS
            USE EMPRESA SHARED
            NEWID = -1
            MAKETRANSACTABLE() 
            
            ISLOCK = FLOCK()
            DO WHILE !ISLOCK
                ISLOCK = FLOCK()
            ENDDO
            
            IF ISLOCK
                BEGIN TRANSACTION
                
                CALC MAX(EMPCOD) TO NEWID 

                IF NEWID >= 0   
                    APPEND BLANK
                    REPLACE EMPCOD WITH NEWID + 1 IN EMPRESA

                    NEWID = EMPRESA.EMPCOD
                ELSE
                    NEWID = -1
                ENDIF
                
                END TRANSACTION
                UNLOCK
            ENDIF
            
            SET REPROCESS TO 0
            RETURN NEWID

El 29 de julio de 2016, 13:42, arquinav <pegg...@gmail.com> escribió:
Reply all
Reply to author
Forward
0 new messages