Enviar datos a Postgres (Conexiones lentas)

99 views
Skip to first unread message

Carlos Hidalgo

unread,
Nov 8, 2016, 8:26:15 PM11/8/16
to Comunidad de Visual Foxpro en Español
Hola a todos

Alguien podría orientarme
Cual seria la forma mas optima de enviar un detalle de factura (por poner un ejemplo) a Postgres, tomando en cuenta que la conexión del cliente es por módem (bastante lenta).

Cuando es un solo registro lo hago asi

PROCEDURE ARTICULO_INSERT_UPDATE 
TextSql=""
TEXT TO TextSql TEXTMERGE NOSHOW
SELECT ARTICULO_INSERT_UPDATE(<<xnCOD>>,'<<xcNom>>','<<xcmed>>',<<xcCAT>>,<<xcMAR>>,<<xncodigousu>>)
ENDTEXT
SQLEXEC(lcCon,TextSql,'ncod')
ENDPROC

En Postgres tengo una función llamada ARTICULO_INSERT_UPDATE que inserta un registro si es nuevo o actualiza si ya existe y al mismo tiempo me retorna el campo serial en una cursor (ncod)

Por medio de un Scan que recorra la tabla y envíe los datos uno por uno podría hacerlo, pero quisiera saber si hay alguna otra forma mas optima.

Saludos
y gracias de antemano
 

Jorge Luis Villanueva

unread,
Nov 8, 2016, 9:56:36 PM11/8/16
to Comunidad de Visual Foxpro en Español
Te conectas por ODBC?

Carlos Hidalgo

unread,
Nov 8, 2016, 10:00:23 PM11/8/16
to publice...@googlegroups.com
Si.
Esta es mi cadena de conexion

lcCon = "Provider=MSDASQL;Driver={PostgreSQL ANSI};SERVER=&lcRutaServer;port=&lcPort;DATABASE=&lcBaseDatos;UID=&lcUser;PWD=&lcPasword;"

mpulla

unread,
Nov 8, 2016, 10:10:42 PM11/8/16
to Comunidad de Visual Foxpro en Español
Hola Carlos

Por lo general trato de hacer todo en funciones.

Create una funcion que te grabe la factura entera, apoyate en JSon y types de postgresql, personalmente creo que es lo mejor 
 
Mira este link te va a dar una idea

Saludos.
Mauricio

Carlos Hidalgo

unread,
Nov 8, 2016, 11:07:41 PM11/8/16
to publice...@googlegroups.com

Gracias..
Voy a revisar... Desconozco al tal Json jejeje..
Soy nuevo en el foro y novato en fox..
Autoaprendizaje  ahi te voy.. Jajaja

Saludos

Carlos Hidalgo

unread,
Nov 9, 2016, 7:18:47 AM11/9/16
to publice...@googlegroups.com
Encontre en la pagina Json.org un archivo para crear el objeto ( o cadena de texto no se si asi se llame)

Haciendo pruebas con el prg que descargue, paso 4 registros de xtabla a una variable textsql..
ahora como hago el INSERT en Postgres desde Foxpro.. 
Podrían ayudarme. Disculpen mi ignorancia...

set procedure to json additive
select MOVIMIENTOS
GO TOP
TextSql=""
DO WHILE NOT RECNO()=4
TextSql=TextSql+recordToJson()
SKIP
ENDDO 
?textsql
genera algo asi:
{"aumenta":1173.35,"codigo":20121130,"codigocuen":23,"disminuye":0,"fecha":"20121130","nombrecuen":"FLUJO DE EFECTIVO"}{"aumenta":300,"codigo":20121130,"codigocuen":28,"disminuye":0,"fecha":"20121130","nombrecuen":"TERRENO"}{"aumenta":33.50,"codigo":20121.......

Y veo que la cadena esta ordenado por el Nombre los campos de la tabla no por la forma en que aparecen en la estructura.. (bueno eso creo que se debe al prg que crea la cadena)

saludos


Martin Paredes

unread,
Nov 9, 2016, 10:54:22 AM11/9/16
to Comunidad de Visual Foxpro en Español
Buen dia, aqui te comparto un ejemplo que como migro masivamente 2 tablas dbf's (invearts e inveprec) a uan DB postgresql.no es la mejor pero fuciona.

SET SAFETY OFF
SET DELETED ON
RELEASE ALL
CLEAR ALL
RELEASE nconn
lcserver="localhost"
lcdatabase="midb"
lcuser="usuario"
lcpassword="contraseña"
lcport="5432"
lcstringConn="Provider=MSDASQL;Driver={PostgreSQL ODBC Driver(UNICODE)}; Server="+lcserver+";Port="+lcport+";Database="+lcdatabase+";uid="+lcuser+";pwd="+lcpassword+";UseServerSidePrepare=1;MaxVarcharSize=254;UnknownsAsLongVarchar=0;TextAsLongVarchar=0;"
SQLSETPROP(0, "Displogin", 3)
_nconn=SQLSTRINGCONNECT(lcstringConn)
ccar=[!&><"'\]
IF _nconn>0 THEN
   SET MESSAGE TO '...Depurando invearts.'
   cini='DELETE FROM mapasoft.invearts;'
   TEXT TO lcSQLcommand NOSHOW TEXTMERGE
       <<cini>>
   ENDTEXT
   IF SQLEXEC(_nconn, lcSQLcommand, "")>0 THEN
      SET MESSAGE TO '...Depurando invecodb.'
      cini='DELETE FROM mapasoft.invecodb;'
      TEXT TO lcSQLcommand NOSHOW TEXTMERGE
         <<cini>>
      ENDTEXT
      IF SQLEXEC(_nconn, lcSQLcommand, "")>0 THEN   
         SET MESSAGE TO '...Depurando audit.'
         cini='DELETE FROM mapasoft.audit WHERE audit.idaudit>0;'
         TEXT TO lcSQLcommand NOSHOW TEXTMERGE
            <<cini>>
         ENDTEXT
         IF SQLEXEC(_nconn, lcSQLcommand, "")>0 THEN
   IF FILE(FULLPATH(CURDIR())+[TEMP\INVEARTS.DBF]) AND FILE(FULLPATH(CURDIR())+[TEMP\INVEPREC.DBF]) THEN
      STORE [] TO csql, cerror
      cini=[INSERT INTO mapasoft.invearts (noarticulo, cvefamilia, cvelinea, cvemarca, codbarras, producto, peso, unidad, localizado, minimo, maximo, ]
      cini=cini+[precompra, poriva, ieps, utilidadp1, utilidadp2, utilidadp3, precio1, precio2, precio3, estatus, foto, inventario, deposito, negativo, ]
      cini=cini+[prelista, descuento1, moneda, noprovedor) ]
      SELECT B
      USE FULLPATH(CURDIR())+[TEMP\INVEPREC.DBF] ALIAS inveprec EXCL
      SELECT A
      USE FULLPATH(CURDIR())+[TEMP\INVEARTS.DBF] ALIAS invearts EXCL
      GO TOP
      IF ! EOF() THEN
         nson=RECCOUNT()
         DO WHILE ! EOF())
            SET MESSAGE TO 'Producto :'+ALLTRIM(invearts.producto)
            SELECT * FROM inveprec WHERE inveprec.noarticulo=invearts.noarticulo INTO CURSOR myinveprec
            IF ! EOF() THEN
               cbarras=[]
               SELECT A
               STORE '' TO c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25,;
                           c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c37, c38, c39, c40, c41, c42, c43, c44, c45, c46, c47, c48, c49, c50
               cc0=[c0="VALUES (']+ALLTRIM[STR[invearts.noarticulo]]+[', "]
               &cc0
               cc1=[c1="']+ALLTRIM[STR[invearts.cvefamilia]]+[', "]
               &cc1
               cc2=[c2="']+ALLTRIM[STR[invearts.cvelinea]]+[', "]
               &cc2
               cc3=[c3="']+ALLTRIM[STR[1]]+[', "]
               &cc3
               cc4=[c4="']+ALLTRIM[cbarras]+[', "]
               &cc4
               cres=''
       FOR nj=1 TO INT(LEN(ALLTRIM(invearts.producto))) STEP 1
         IF SUBSTR(invearts.producto, nj, 1)$ccar THEN
      LOOP
   ELSE
      cres=cres+SUBSTR(invearts.producto, nj, 1)
   ENDIF
   ENDFOR
   cc5=[c5="']+ALLTRIM[cres]+[', "]
               &cc5  
   cc6=[c6="']+ALLTRIM(TRANSFORM[invearts.peso, '9999999.999'])+[', "]
             &cc6
   cc7=[c7="']+ALLTRIM[STR[invearts.unidad]]+[', "]
               &cc7
   cc8=[c8="']+ALLTRIM[invearts.localizado]+[', "]
               &cc8
               cc9=[c9="']+ALLTRIM[TRANSFORM[invearts.minimos, '9999999999999.9999']]+[', "]
               &cc9
               cc10=[c10="']+ALLTRIM[TRANSFORM[invearts.maximos, '9999999999999.9999']]+[', "]
               &cc10
               cc11=[c11="']+ALLTRIM[TRANSFORM[myinveprec.precomreal, '9999999999999.9999']]+[', "]
               &cc11
               cc12=[c12="']+ALLTRIM[TRANSFORM[myinveprec.iva, '9999999.999']]+[', "]
               &cc12
               cc13=[c13="']+ALLTRIM[TRANSFORM[myinveprec.ieps, '9999999.999']]+[', "]
               &cc13
               cc14=[c14="']+ALLTRIM[TRANSFORM[myinveprec.utilidadn, '9999999.999']]+[', "]
               &cc14
               cc15=[c15="']+ALLTRIM[TRANSFORM[myinveprec.utilidade, '9999999.999']]+[', "]
               &cc15
               cc16=[c16="']+ALLTRIM[TRANSFORM[myinveprec.utilidadp, '9999999.999']]+[', "]
               &cc16
               cc17=[c17="']+ALLTRIM[TRANSFORM[myinveprec.preunonor, '9999999999999.9999']]+[', "]
               &cc17
               cc18=[c18="']+ALLTRIM[TRANSFORM[myinveprec.preunoesp, '9999999999999.9999']]+[', "]
               &cc18
               cc19=[c19="']+ALLTRIM[TRANSFORM[myinveprec.preunopic, '9999999999999.9999']]+[', "]
               &cc19
               cc20=[c20="']+ALLTRIM[STR[invearts.estatus]]+[', "]
               &cc20
               cc21=[c21="']+ALLTRIM[invearts.foto]+[', "]
               &cc21
               cc22=[c22="']+IIF(invearts.inventario=.T., 'TRUE', 'FALSE')+[', "]
               &cc22
               cc23=[c23="']+IIF(invearts.deposito=.T., 'TRUE', 'FALSE')+[', "]
               &cc23
               cc24=[c24="']+IIF(invearts.negativo=.T., 'TRUE', 'FALSE')+[', "]
               &cc24
               cc25=[c25="']+ALLTRIM[TRANSFORM[myinveprec.precompra, '9999999999999.9999']]+[', "]
               &cc25
               cc26=[c26="']+ALLTRIM[TRANSFORM[myinveprec.porcdesc, '9999999.999']]+[', "]
               &cc26
               cc27=[c27="']+IIF(myinveprec.moneda=[P], ALLTRIM(STR(1)), ALLTRIM(STR(2)))+[', "]
               &cc27
               cc28=[c28="'1'"]
               &cc28 &&noprovedor
               csql=c0+c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+c11++c12+c13+c14+c15+c16+c17+c18+c19+c20+c21+c22+c23+c24+c25+c26+c27+c28+[);]
               TEXT TO lcSQLcommand NOSHOW TEXTMERGE
                  <<cini>>
                  <<csql>>
               ENDTEXT
               IF SQLEXEC(_nconn, lcSQLcommand, "")<=0 THEN
                  MESSAGEBOX(lcSQLcommand)
                  =AERROR(laError)
                  cError='F-'+laError(1,3)
                  MESSAGEBOX(cError)
                  EXIT
               ENDIF
            ENDIF
            SELECT invearts
            SKIP
         ENDDO
         SET MESSAGE TO '...Depurando audit.'
         IF INT(LEN(ALLTRIM(cerror)))<1 THEN
            cini='DELETE FROM mapasoft.audit;'
                     TEXT TO lcSQLcommand NOSHOW TEXTMERGE
                        <<cini>>
                     ENDTEXT
                     IF SQLEXEC(_nconn, lcSQLcommand, "")>0 THEN
                        SET MESSAGE TO ''
                        MESSAGEBOX('Listo...')
                     ELSE
                        SET MESSAGE TO ''
                        =AERROR(laError)
                        cError='E-'+laError(1,3)
                        MESSAGEBOX(cError)
                     ENDIF
         ENDIF
               ELSE
                  MESSAGEBOX('Error; La Tabla Invearts No Tiene Ningun Registro...', 16, 'Mensaje.', 5000)
               ENDIF
               USE IN SELECT("MYINVEPREC")
               USE IN SELECT("INVEARTS")
               USE IN SELECT("INVEPREC")
            ELSE
               MESSAGEBOX('Error; No Existe El Origen De Datos, Invearts-Inveprec-Invecodb.', 16, 'Mensaje.')
            ENDIF
         ELSE
            SET MESSAGE TO ''
            =AERROR(laError)
            cError='C-'+laError(1,3)
            MESSAGEBOX(cError)         
         ENDIF
      ELSE
         SET MESSAGE TO ''
         =AERROR(laError)
         cError='C-'+laError(1,3)
         MESSAGEBOX(cError)
      ENDIF
   ELSE
      SET MESSAGE TO ''
      =AERROR(laError)
      cError='B-'+laError(1,3)
      MESSAGEBOX(cError)
   ENDIF
ELSE
   SET MESSAGE TO ''
   =AERROR(laError)
   cError='A-'+laError(1,3)
   MESSAGEBOX(cError)
ENDIF
SET MESSAGE TO ''
SET SAFETY ON
RELEASE ALL
CLEAR ALL
CLEAR MEMORY
RELEASE nconn


*** Si ocupas algo mas, favor de solicitarlo es este hilo.

Slds....
Mapasac
General Escobedo, N.L. Mexico

El martes, 8 de noviembre de 2016, 19:26:15 (UTC-6), Carlos Hidalgo escribió:

Carlos Hidalgo

unread,
Nov 9, 2016, 11:18:15 AM11/9/16
to publice...@googlegroups.com
Gracias Martin

asi lo estoy haciendo, pero quisiera ver si hay otra forma mas optima..mientras tanto sigo con esta.

PROCEDURE Compra_INSERT
***empezamos con armar el detalle
LOCAL lcCadena, lnRegistros, lnContador, lcValues
SELECT Detalle &&detalle de la compra
GO top
lcCadena=""
lnRegistros=reccount()
lnContador=0
lcValues=""
SCAN
lcCadena="(";
+ALLTRIM(STR(codigo));
+","+ALLTRIM(STR(orden));
+","+ALLTRIM(STR(CodigoArt));
+","+ALLTRIM(STR(cantidad,12,2));
+","+ALLTRIM(STR(total,12,2));
+","+ALLTRIM(STR(iva,12,2));
+")"
lnContador=lnContador+1
IF lnRegistros>lnContador
lcValues=lcValues+lcCadena+","
ELSE
lcValues=lcValues+lcCadena
ENDIF
ENDSCAN
TextSql=""
TEXT TO TextSql TEXTMERGE NOSHOW
DELETE FROM DetalleCom WHERE codigo=<<xcod>>; 
INSERT INTO DetalleCom VALUES <<lcValues>>; 
SELECT Compra_INSERT(<<xcod>>,'<<xser>>',<<xNum>>,'<<xfec>>',<<xPro>>,<<xTie>>',<<xcodigousu>>)
ENDTEXT
SQLEXEC(lcCon,TextSql,'Nxcod')
pcmensaje="Datos Guardados Exitosamente!"
DO Actualiza_Compra
ENDPROC

Germán Fabricio Valdez

unread,
Nov 9, 2016, 5:26:38 PM11/9/16
to Comunidad de Visual Foxpro en Español
lo que tienes que hacer es un EXE separado del programa que se encargue de enviar informacion al servidor

lo puedes poner como una tarea programada en windows

vas mandando por registro y marcas en tu tabla que fue enviado

tenes que usar el TRY ENDTRY para controlar posible errores de conexion o de envio al servidor para que el proceso no se detenga y siempre que encuentre el servidor envie datos y si hay error no marcas el registro como enviado

Carlos Hidalgo

unread,
Nov 9, 2016, 9:11:04 PM11/9/16
to publice...@googlegroups.com
Gracias Germán
Estoy usando la version  7 de foxpro, no encuentro ese comando.
TRY ENDTRY  en la ayuda.. 

La idea de mandar registro por registro me parece lo mejor, mientras sigo con la ejecución del programa principal.

Podrías apoyarme con algún ejemplo sencillo.. (perdona mi inexperiencia, es que hasta hace tres meses que a empecé a usar Postgres con Foxpro, siempre había trabajado con tablas nativas, Gracias a eso encontré el Foro y me uní. No me arrepiento)
 
Saludos


mpulla

unread,
Nov 9, 2016, 10:05:44 PM11/9/16
to Comunidad de Visual Foxpro en Español
Hola Carlos.

En VFP 9.0 encuentras Try te facilita la vida.

Te paso un ejemplo, creo un string con datos de una tabla, luego ejecuto una función que recibe el string lo transforma a CTE y actualiza la tabla, la ventaja es que haces un llamado y actualizas cuantos registros pases todo esto en un transacción todo o nada.

Saludos.
Mauricio

select item, cantidad;
 from c:\temp\items;
  Where fabricados;
Into curso rsitems

*Función en postgresql
local lcSql As String
lcSql = [Select * From inventarios.item_existencia(?lcJSon)]

*Creo el string que contiene el JSON
private lcJSon As String
lcJSon = []
Scan
lcJSon = lcJSon + [{"itm":"] + alltrim(rsitems.item) + [","cnt":] + iif(Empty(rsitems.cantidad), '0.000', Alltrim(Str(rsitems.cantidad, 15, 3))) + [},]
endscan
lcJSon = '[' + substr(lcJSon, 1, len(lcJSon)-1) + ']'

if SqlExec(Thisform.iHandle, lcSql, "RsResultado") = -1
aError(laError)
messagebox(laError(2))
Else 
messagebox("OK")
endif 



CREATE OR REPLACE FUNCTION inventarios.item_existencia(p_items_json character varying)
  RETURNS void AS
$BODY$

BEGIN 

With t (itm, cnt)
As 
(
Select itm, cnt
From 
json_populate_recordset (null::inventarios.items_existencia_type, p_items_json::json)
)
Update inventarios.items i
   Set existencia = t.cnt
 From t 
  WHERE i.item = t.itm
 
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;


CREATE TYPE inventarios.items_existencia_type AS
   (itm character varying(15),
    cnt numeric(12,3));

Carlos Alfaro

unread,
Nov 9, 2016, 10:05:53 PM11/9/16
to publice...@googlegroups.com

Exactamente 7 no tiene Try.

 

Tenés alguna razón para usar esa versión?

Carlos Hidalgo

unread,
Nov 9, 2016, 11:09:47 PM11/9/16
to publice...@googlegroups.com

Muchas Gracias por el ejemplo..
Voy a analizarlo e implementarlo.
Cualquier duda te cuento..
Saludos
Carlos Alfaro La versión 7 esta en español.. Se me hace mas facil ya que no poseeo muchos conocimientos de fox.

Reply all
Reply to author
Forward
0 new messages