Actualizar datos desde un Cursor a SQL Server 2019

305 views
Skip to first unread message

integral

unread,
Nov 24, 2025, 10:30:40 AMNov 24
to Comunidad de Visual Foxpro en Español
Que tal amigos 

Muy Buenos Dias

Quiero actualizar algunos registros desde VFP9 a SQL Server 2019 desde un Cursor...

Venia utilizando lo siguiente :

TEXT To lcSQL_UP NOSHOW
   UPDATE dbo.Prestamos
      SET ...
ENDTEXT
IF SQLExec(cn. lcSQL_UP_04) < 1
    = AERROR(laerror)
...
ENDIF

Buscando hoy cierta información encontré el siguiente ejemplo  Con algunos Comandos que No vengo utilizando.

Aquí les muestro el ejemplo del código que encontré

SELECT tu Tabla o Cursor

* Variables a Grabar

nID = TuTabla.ID
nNombre = TuTabla.Nombre
nTelefono = TutTabla.Telefono
...

ThisForm.Conectar && Conecta con la DB SQL Server o bien crea la conexion a SQL

= SQLSETPROP(lnHandle,'Transactions',2) && Iniciamos la transaccion

TEXT TO lcSQL NOSHOW
     INSERT INTO TBLTABLA (ID,Nombre,Telefono)
           VALUES (?nID,?nNombre,?nTelefonor)
ENDTEXT

IF SQLEXEC(lnHandle,lcSQL)<0
    IF AERROR(laError)>0
         Menssagebox( laError[2])
    ENDIF
ENDIF

IF SQLCOMMIT(lnHandle) > 0    && Confirma los cambios
    * && Aquí nada, ya que significa que se realizo exitosamente
ELSE
   IF AERROR(laError)>0
       SQLROLLBACK(lnHandle)   && Deshacemos los cambios
       Messagebox ( laError[2])
   ENDIF
ENDIF

Agradezco sus comentarios y sugerencias

Saludos,

Integral

integral

unread,
Nov 28, 2025, 9:50:09 AMNov 28
to Comunidad de Visual Foxpro en Español
Que tal amigos 

Muy Buenos Días

Grabo los cambios que se realizan en cada registro .Pero esta sucediendo algo extraño.

La tabla principal tiene 35 campos. Actualizo algunos registros desde VFP9 a SQL Server 2019 desde un Cursor...

Utilizo el siguiente código :

  TEXT TO lcSQL_UP_05 TEXTMERGE NOSHOW
   UPDATE dbo.prestamos
 SET fech_regis  = ?m.fech_regis,
          registro      = ?m.registro,
          cod_pres   = ?m.cod_pres,
...
  ...
...
          obs           = ?m.obs       && Hasta completar los 35 campos
 WHERE registro = ?m.registro
  ENDTEXT

Y me aparece el siguiente mensaje ...

ERROR_MESSG_01.jpg 
 
Aquí viene lo extraño. Si solo indico en el código del UPDATE solo 16 campos. No me muestra el mensaje del error y
graba perfectamente los cambios realizados.

MESSG_GRABO.jpg

Busque información sobre el =MessageBox y leí que soporta a 1024 caracteres de lo contrario se truca el mensaje...

Agradezco sus comentarios y sugerencias.

Saludos,

Integral

Gerardo Cagnola

unread,
Nov 28, 2025, 10:39:50 AMNov 28
to publice...@googlegroups.com
es el tamaño del string del update, está "truncado" la sentencia

--
Blog de la Comunidad Visual FoxPro en Español http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.
Para ver este debate, visita https://groups.google.com/d/msgid/publicesvfoxpro/8e85e83b-b589-439c-8d5f-a274bc21480fn%40googlegroups.com.

Wagner Cevallos

unread,
Nov 28, 2025, 11:18:52 AMNov 28
to publice...@googlegroups.com
Creo que para que evites el desbordamiento de texto , utiliza un procedimiento almacenado  que diseñes en SQL y lo llamas desde VFP

--
Blog de la Comunidad Visual FoxPro en Español http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.
Para ver este debate, visita https://groups.google.com/d/msgid/publicesvfoxpro/8e85e83b-b589-439c-8d5f-a274bc21480fn%40googlegroups.com.


--
Ing. Wagner Javier Cevallos  Macías
0985303564-0996496512
Portoviejo-Manabí-Ecuador

Gerardo Cagnola

unread,
Nov 28, 2025, 11:23:47 AMNov 28
to publice...@googlegroups.com
35 campos a actualizar??? too much
podrías revisar que dato se actualizó y cual no, y recién ahí armás el update


elkin dario uribe torres

unread,
Nov 28, 2025, 11:45:07 AMNov 28
to publice...@googlegroups.com
Buenos días.

Pueden ser muchos los campos, pero a veces necesarios.  En mi caso para un software se necesitaron actualizar 41 campos y tenia ese problema y un amigo que se llama Luis Horacio me recomendó no volver a utilizar la instrucción:

TEXT TO lcSQL_UP_05 TEXTMERGE NOSHOW
ENDTEXT

Que la cambiara por esta

set textmerge on TO memvar lcStringSQL noshow
set textmerge to

y desde ahí la vengo utilizando y no he tenido problemas.

Cordialmente

Elkin uribe

integral

unread,
Nov 28, 2025, 12:01:17 PMNov 28
to Comunidad de Visual Foxpro en Español
Que tal amigos del Foro

Gracias por sus comentarios y  sugerencias.

Colega Elkin Uribe, estuve buscando y leyendo información a cerca de este comando.  Fue a partir de VFP 7.0 que se comenzó a utilizar.

En versiones anteriores se utilizaba el comando que sugieres.

SET Textmerge on TO

Encontré también un articulo donde mencionan utilizar el PRETEXT...

Si no funciona con ello, tendré que utilizar tu sugerencia.

Atte.

Integral

Mik

unread,
Nov 28, 2025, 12:07:39 PMNov 28
to Comunidad de Visual Foxpro en Español
Yo estilo usarlo así:

TEXT TO myCommand NOSHOW PRETEXT 15

ENDTEXT

El TEXTMERGE solo lo uso cuando voy a escribir en el comando el valor de alguna variable <<myVariable>>

Quiza te sirva!

Saludos!!

integral

unread,
Nov 28, 2025, 11:55:51 PMNov 28
to Comunidad de Visual Foxpro en Español
Que tal amigos

Muy Buenas Noches

El siguiente código fue la solución a mi problema.

TEXT TO lcSQL_UP_05 TEXTMERGE NOSHOW PRETEXT 15
....
ENDTEXT 

ó

TEXT TO lcSQL_UP_05 TEXTMERGE NOSHOW PRETEXT 2+4+8
...
ENDTEXT

Hasta la próxima.

Saludos,

Integral

DSánchez

unread,
Nov 29, 2025, 9:40:46 PMNov 29
to Comunidad de Visual Foxpro en Español
Hola Integral

Y porque no te vas hacer store procedure mejor,  en mi caso me paso algo raro  con  = SQLSETPROP(lnHandle,'Transactions',2) && Iniciamos la transaccion 
no me confiaria de esto en un sistema con muchas concurrencias y mas donde hay problemas de conectividad inestabilidad de luz y grabando tablas encabezados y detalles.

Mejor migrar a store procedure ahora con un curso que tomes en udemy u otro lado, mas la I.A. avanzas rapido.

Saludos

Esteban Herrero

unread,
Nov 30, 2025, 8:08:41 AMNov 30
to publice...@googlegroups.com

Es así Douglas, en todos los motores están los Store Procedures, xq no usarlos, p eso están. Simplifica el código.

Con respecto a las Transacciones, SIEMPRE usar transacciones Manuales sin dudarlo a esto.

Si estas teniendo problemas es xq quizás estas definiendo mal el Modo antes del Select/Update.

No utilizo mucho SqlServer pero creo q el modo es "isolation level serializable", no recuerdo bien si tanto p Select/Update, en FB utilizo distintos modos ya sea p Update o Select.

Saludos

--
Blog de la Comunidad Visual FoxPro en Español http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.

Dsan

unread,
Nov 30, 2025, 10:52:11 AMNov 30
to publice...@googlegroups.com
Hola buen dia.

Claro de acuerdo con usted Esteban,  ese tema lo tengo muy claro, en el grupo me apoye mucho con los manuales y 2 que 3 que recuerdo presentaciones de Miguel Antunez, 
pero mas que escribir código, con clientes que no tiene muchos recursos hay que saber implementar desde la codificación hasta la configuración del servidor en este caso SQL Server, y hasta que me tome un cursos dba pues aprendí esa lección no solo es codificación, sino también saber instalar y configurar el motor que sea. 

Y aprendí a la mala, y pues trabajar de lado del servidor es lo más correcto más que las api odbc vienen cambiando y nuestro vfp vienen quedando atrás, en mi caso ya hace un poco más de tres año usando vfp advanced que por mucho no estén de acuerdo con su uso, pero tengo la alternativa de reportar bugs y me solucionen, algo que no tenemos en vfp9.  lógico mientras se va avanzando en otra plataforma, para escritorio pos vfp/vfp advanced.

Pero al final mi recomendación para el colega Integral,  es no confiarse en la transacción sino hacerlo todo transaccional del lado del servidor en el motor que se use.

saludos

DSanchez


Has recibido este mensaje porque estás suscrito a un tema del grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/publicesvfoxpro/CdnF2b_DZ9Q/unsubscribe.
Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a publicesvfoxp...@googlegroups.com.
Para ver este debate, visita https://groups.google.com/d/msgid/publicesvfoxpro/3936f6b6-6569-491b-a12f-f0690abe8ab8%40yahoo.com.ar.

mpulla

unread,
Dec 2, 2025, 9:28:34 AMDec 2
to Comunidad de Visual Foxpro en Español
Hola Integral.

Como te recomiendan algunos colegas es mejor manejarlo en la base de datos, hace mucho generaba un xml con todos los datos que necesitaba al mandar a grabar, paso el xml a sql server y el lo procesaba.

Con json es mas liviano, mira este ejemplo.

CREATE PROCEDURE sp_Productos_iu
    @Productos NVARCHAR(MAX)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
        BEGIN TRANSACTION;

        SELECT
            JSON_VALUE(value, '$.ItemId') AS ItemId,
            JSON_VALUE(value, '$.Nombre') AS Nombre,
            JSON_VALUE(value, '$.Precio') AS Precio,
        INTO #ProductosTemp
        FROM OPENJSON(@Productos);

        MERGE INTO Productos AS Target
        USING #ProductosTemp AS Source
        ON (Target.ItemId = Source.ItemId)
        WHEN MATCHED THEN
            UPDATE SET
                Target.Nombre = Source.Nombre,
                Target.Precio = Source.Precio,
                Target.FechaActualizacion = GETDATE()
        WHEN NOT MATCHED BY TARGET THEN
            INSERT (ItemId, Nombre, Precio)
            VALUES (Source.ItemId, Source.Nombre, Source.Precio);

        DROP TABLE #ProductosTemp;

        COMMIT TRANSACTION;

    END TRY
   
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
       
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT
            @ErrorMessage = ERROR_MESSAGE(),
            @ErrorSeverity = ERROR_SEVERITY(),
            @ErrorState = ERROR_STATE();

        RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
    END CATCH
END;

Saludos.
Mauricio
El lunes, 24 de noviembre de 2025 a las 10:30:40 UTC-5, integral escribió:

integral

unread,
Dec 11, 2025, 4:39:02 PM (11 days ago) Dec 11
to Comunidad de Visual Foxpro en Español

Que tal Amigos :

Muy Buenas Tardes.

Gracias amigo Mauricio por el ejemplo, quisiera primero aprender a crear y utilizar un SP para actualizar registros desde VFP a 
SQL Server 2019 

Aquí un pequeño ejemplo que encontré

*-- 1. Definición del Stored Procedure original (en SQL Server)
CREATE PROCEDURE sp_MiEjemploVFP
    @ID INT,
    @NuevoValor VARCHAR(50)
AS
BEGIN
    UPDATE MiTabla SET MiColumna = @NuevoValor WHERE ID = @ID;
END

Tendrás algún ejemplo mas completo que me sirva de guía.

Saludos,

Integral

Victor Espina

unread,
Dec 12, 2025, 10:59:02 AM (11 days ago) Dec 12
to Comunidad de Visual Foxpro en Español
Este es un codigo real que esta en produccion. Ojala te sirva de ejemplo.  Un punto que quiero destacar es este codigo:

 DECLARE @_licencsePlate CHAR(10) = @licensePlate,
         @_vin CHAR(20) = @vin,
         @_email VARCHAR(360) = @email

la razon de esto es evitar algo conocido como "parameter sniffing".  Cuando SQL Server ejecuta el SP por primera vez, calcula un plan de ejecucion para cada uno de los queries involucrados, usando los valores pasados a los parametros en ESA vez... como consecuencia, el plan puede estar optimizado para un vallor especifico y esto causa que cuando el valor del parametro cambia el plan ya no sea el mas adecuado, causando que el SP consuma mucho mas tiempo con algunos valores que con otros.  

Para evitar esto y forzar a que SQL Server genere un plan de ejecucion mas "generico", se debe evitar usar los parametros directamente en los queries dentro del SP.

-- spCarRegister
-- Registra un nuevo vehiculo en la cuenta del cliente
--
IF OBJECT_ID('spCarRegister','P') IS NOT NULL
  DROP PROCEDURE spCarRegister
GO
CREATE PROCEDURE [dbo].[spCarRegister](
 @licencePlate CHAR(10),
 @vin CHAR(20),
 @email VARCHAR(360)
) AS BEGIN
 
 DECLARE @error INTEGER = 0,
         @msgerror VARCHAR(max) = ''

 DECLARE @_licencsePlate CHAR(10) = @licensePlate,
         @_vin CHAR(20) = @vin,
         @_email VARCHAR(360) = @email

 IF LEN(@licencePlate) = 0 BEGIN
   SELECT @error = -1,
          @msgerror = N'Debe indicar la placa del vehículo.'
   RAISERROR(@msgerror,14,1)
   RETURN @error
 END

 IF LEN(@vin) = 0 BEGIN
   SELECT @error = -1,
          @msgerror = N'Debe indicar el VIN del vehículo.'
   RAISERROR(@msgerror,14,1)
   RETURN @error
 END

 IF LEN(@email) = 0 BEGIN
   SELECT @error = -1,
          @msgerror = N'Debe indicar eMail.'
   RAISERROR(@msgerror,14,1)
   RETURN @error
 END

 IF NOT EXISTS (SELECT * FROM Customers WHERE cstEmail = @email) BEGIN
   SELECT @error = -1,
          @msgerror = N'El eMail indicado no se encuentra registrado.'
   RAISERROR(@msgerror,14,1)
   RETURN @error
 END

 IF EXISTS (SELECT * FROM Customers WHERE cstEmail = @email AND cstStatus != 'COMPLETADO') BEGIN
   SELECT @error = -1,
          @msgerror = N'El eMail indicado no ha completado el registro.'
   RAISERROR(@msgerror,14,1)
   RETURN @error
 END

 DECLARE @LastCode int,
         @validationCode int,
         @vehStatus CHAR(15),
         @vehId INT,
         @cstEmail VARCHAR(max)


 -- Verificamos si el vehiculo esta registrado, su status y un teorico
 -- codigo de activacion
 SELECT @vehId = vehId, @vehStatus = vehStatus, @validationCode = vehValidationCode, @cstEmail = cstEmail
   FROM Vehicles
  WHERE vehLicencePlate = @_licencePlate
    AND vehVin = @_vin


 IF (@vehStatus IS NOT NULL AND @cstEmail <> @email AND @vehStatus<>'ELIMINADO') BEGIN
   SELECT @error = -1,
          @msgerror = N'El vehículo indicado ya fué registrado por otro usuario.'
   RAISERROR(@msgerror,14,1)
   RETURN @error
 END


 IF (@vehStatus IS NOT NULL AND @vehStatus = 'COMPLETADO') BEGIN
   SELECT @error = -1,
          @msgerror = N'El vehículo indicado ya se encuentra registrado.'
   RAISERROR(@msgerror,14,1)
   RETURN @error
 END


 -- Si el auto no esta registrado, se valida que el vehiculo exista y no se haya vendido
 IF @vehStatus IS NULL BEGIN
   DECLARE @numfactura CHAR(15)
   SELECT TOP 1 @numfactura = CASE WHEN b.numfactura IS NULL THEN '*IMPORTADO*' ELSE b.numfactura END
     FROM ctavehiculos a WITH (NOLOCK)
     LEFT JOIN ctabillof b WITH (NOLOCK) ON b.chasis = a.vin
    WHERE a.vin = @_vin
      AND a.placa = @_licencePlate

   IF @numfactura IS NULL BEGIN
     SELECT @error = -1,
            @msgerror = N'La placa y el VIN del vehículo son incorrectos o no están registrados.'
     RAISERROR(@msgerror,14,1)
     RETURN @error
   END
   IF @numfactura = '' BEGIN
     SELECT @error = -1,
            @msgerror = N'La placa y el VIN del vehículo corresponden a un auto no vendido aún.'
     RAISERROR(@msgerror,14,1)
     RETURN @error
   END
 END


 -- Si el vehiculo no esta registrado o su status no es PENDIENTE o no tiene un codigo de activacion, se genere
 -- un nuevo codigo de activacion
 IF @vehStatus IS NULL OR @vehStatus <> 'PENDIENTE' OR @validationCode IS NULL BEGIN
   SET @validationCode = NULL
   WHILE @validationCode IS NULL BEGIN
     SET @LastCode = ROUND(RAND()*1000000,0)
     IF @LastCode BETWEEN 100000 AND 999999 AND NOT EXISTS (SELECT * FROM Vehicles WHERE vehValidationCode IS NOT NULL AND vehValidationCode = @LastCode)
       SET @validationCode = @LastCode
   END
 END

 DECLARE @mailid INT
 IF @@ERROR = 0 AND @vehStatus IS NOT NULL AND @vehStatus<>'COMPLETADO' BEGIN
   UPDATE Vehicles
      SET vehStatus = 'PENDIENTE',
          cstEmail = @email,
          vehValidationCode = @validationCode,
          rowLastupd = GETDATE()
    WHERE vehLicencePlate = @_licencePlate
      AND vehVin = @_vin
 END
 
 IF @@ERROR = 0 AND @vehStatus IS NULL BEGIN
    INSERT INTO Vehicles (
      vehLicencePlate,vehVin,vehStatus,vehValidationCode,
      cstEmail,rowStatus,rowLastupd
    ) SELECT
      @_licencePlate,@_vin,'PENDIENTE',@validationCode,
      @email,'1',GETDATE()

    IF @@ERROR = 0
      SET @vehId = SCOPE_IDENTITY()    
 END
 
 IF @@ERROR = 0 BEGIN
   DECLARE @body VARCHAR(max)
   SET @body = 'Su código de validación es: ' + CAST(@validationCode AS VARCHAR)
   EXEC @mailid = EMDB..spTMMQPostEx 'Reportes',@email,'Confirmación de registro de vehículo',@body,NULL
 END ELSE BEGIN
   SELECT @validationCode = NULL,
          @error = @@ERROR,
          @msgerror = ERROR_MESSAGE()
   RETURN @error
 END

 
 SELECT vehId,vehLicencePlate,vehVin,vehStatus,cstEmail,vehValidationCode,@mailid AS mailid
   FROM Vehicles
  WHERE vehId = @vehId

END
GO


Saludos

Victor Espina

integral

unread,
Dec 12, 2025, 2:21:09 PM (11 days ago) Dec 12
to Comunidad de Visual Foxpro en Español
Que tal Amigos :

Muy Buenas Tardes.

Gracias amigo Victor Espina por el ejemplo mostrado, algo mas elaborado pero toda una clase del tema.

Y que parámetros se debe indicar para llamar al SP desde VFP9 

Siempre tomo en cuanta sus comentarios y sugerencias...

Saludos,

Integral

Victor Espina

unread,
Dec 12, 2025, 2:52:24 PM (11 days ago) Dec 12
to Comunidad de Visual Foxpro en Español
Los parametros los define el SP.  La forma de llamarlo desde VFP es:

cCmd = "EXEC nombre_sp ?param1, ?param2,  ..., ?paramN"

donde param1, param2, paramN son variables privadas que deben estar definidas e inicializadas con sus valores antes de ejecutar el comando con SQLEXEC().  

Victor Espina

Hendell Mora

unread,
Dec 12, 2025, 3:05:05 PM (11 days ago) Dec 12
to publice...@googlegroups.com
frm13=conectar_db(_screen.cn1)
x1=ALLTRIM(thisform.txt_codigo.value)
x2=ALLTRIM(frm13_cur_pv.codigo_pv)
x3=frm13_cur_pv.activo
SQLEXEC(frm13,"call usp_guardar_producto_pv(?x1,?x2,?x3);")
desconectar_db(frm13)

--
Blog de la Comunidad Visual FoxPro en Español http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.

Hendell Mora

unread,
Dec 12, 2025, 3:11:40 PM (11 days ago) Dec 12
to publice...@googlegroups.com
en MYSQL

Miguel Antúnez

unread,
Dec 12, 2025, 3:16:33 PM (11 days ago) Dec 12
to publice...@googlegroups.com
Estimado Integral, te invito a ver este par de videos, se habla mucho del tema.


Saludos.


--
Blog de la Comunidad Visual FoxPro en Español http://comunidadvfp.blogspot.com
---
Has recibido este mensaje porque estás suscrito al grupo "Comunidad de Visual Foxpro en Español" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a publicesvfoxp...@googlegroups.com.


--
Reply all
Reply to author
Forward
0 new messages