FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Copia de registros con FWH
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Copia de registros con FWH
Posted: Tue May 30, 2017 10:10 AM
Buenas os dejo un tip por si es de ayuda.

Hoy he tenido que traspasar datos de una tabla a otra, pero con el problema añadido que es que quiero marcar el registro traspasado como procesado.
No he logrado hacerlo como quería con el APPEND FROM .... pues no tenemos el control sobre la tabla origen, y necesito marcarla.

Mirando en la clase DATABASE de FW, me encuentro con un par de funciones que vienen de perlas, pero no hay ejemplo , pues podemos uno;

Code (fw): Select all Collapse
  USE "ORIGEN" NEW 
 ::oDbfOrigen := TDataBase():New()

  USE "DESTINO" NEW 
  ::oDbfDestino := TDataBase():New()

  while !::oDbfOrigen:eof()
     dbselectarea( ::oDbfOrigen:cAlias )
     if !::oDbfOrigen:PROCESADA
        hRec := FW_RecToHash( )
       
        dbselectarea( ::oDbfDestino:cAlias )
        append blank
        FW_HashToRec( hRec )
     endif   
     
     dbselectarea( ::oDbfOrigen:cAlias )
     ::oDbfOrigen:PROCESADA := .T.
     ::oDbfOrigen:Save()

     ::oDbfOrigen:Skip()
  end while


La función FW_RecToHash( ), me devuelve un hash con los datos del registro actual de la tabla activa.
Así, una vez obtenido, cambia a la tabla destino hacemos un append blank, y soltamos el contenido ;
FW_HashToRec( hRec )

A continuación, marca ya en la tabla origen que lo he procesado.
De esta manera, tenemos un control total sobre el traspaso de datos que con APPEND FROM.
Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Copia de registros con FWH
Posted: Tue May 30, 2017 02:40 PM
Pues me aprovecho de la situacion y pongo la mia, que tiene como caracteristicas:

- Permite que dbfs origen no tengan todos los mismos campos o no esten en el mismo orden.
- Hipervelocidad :-)
- Compatible Harbour/ xHarbour / Clipper


Code (fw): Select all Collapse
FUNCTION Main()

   LOCAL nI, aPar, nLast

   SELECT 0
   USE Test1
   nLast:= LastRec()

   SELECT 0
   USE Test2
  
   FOR nI:= 1 TO nLast
     
      Test1-> ( dbGoto( nI) )
     
      APPEND BLANK
   
      aPar:= CopRegHiperVelocidad("Test1", Alias(), aPar)

   NEXT

RETURN NIL


FUNCTION CopRegHiperVelocidad(cAliOri, cAliDes, aPar)
   Local nI
   Local nFCount
   Local nPosOri
   Local cCampo
   
   IF aPar == NIL

      aPar:= {}

      nFCount:= (cAliDes)-> (FCount())

      #Define FG_(cAlias, nPos) ((cAlias)-> (FieldGet(nPos)))

      FOR nI:= 1 TO nFCount
         cCampo:= (cAliDes)-> (FieldName(nI))
         
         nPosOri:= (cAliOri)-> ( FieldPos(cCampo))

         IF nPosOri != 0

            (cAliDes)-> ( FieldPut(nI, FG_(cAliOri, nPosOri)))

            Aadd(aPar, {nI, nPosOri})

         ENDIF

      NEXT
   ELSE
      // La segunda y posterior vez: hipervelocidad

      nFCount:= Len(aPar)

      FOR nI:= 1 TO nFCount

         (cAliDes)-> ( FieldPut(aPar[nI, 1], FG_(cAliOri, aPar[nI, 2])))

      NEXT

   ENDIF

RETURN aPar
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Copia de registros con FWH
Posted: Tue May 30, 2017 06:44 PM

Mañana lo pruebo.
Haciendo pruebas de rendimiento me encuentro que append from tarda menos de un segundo, siendo la otra opción más de 45 segundos en
las mismas circunstancias, por lo tanto, voy a tener que rediseñarlo.

A tu hipervelocidad, si en vez de pasarle el array, creas una static a un hash, seria un poquito más elegante ;-)

Saludos

Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Copia de registros con FWH
Posted: Tue May 30, 2017 08:41 PM
Parece que mi hipervelocidad es una lisiada comparada con __dbTrans() :-)

Code (fw): Select all Collapse
/* __dbTrans( nDstArea, aFieldsStru, bFor, bWhile, nNext, nRecord, lRest ) -> <lSuccess> */

HB_FUNC( __DBTRANS )



https://github.com/harbour/core/blob/d8c6c562f3e5815217abeec5e145432bcff3e6df/src/rdd/dbcmd.c

No debe ser difícil de adaptarla a cualquiera de las funciones de arriba. Además del código C, mas veloz, el copiar campo a campo mata la eficiencia.
Posts: 728
Joined: Fri Oct 07, 2005 07:38 AM
Re: Copia de registros con FWH
Posted: Wed May 31, 2017 10:32 AM

Me encanta la hipervelocidad, hace bastantes años me estuve peleando con el tema de los traspasos entre tablas (básicamente para poder actualizar automáticamente las bases de datos de mis aplicaciones en los clientes). Tuve que pasar del APPEND FROM a pesar de su gran rapidez porque como hubiera un cambio en el tipo de datos, por ejemplo de carácter a numérico reventaba de lo lindo. De este modo tuve que crearme una función que controlara esto, además de ver si algún campo numérico había disminuido de tamaño, etc ... con lo que conseguí un proceso súper-robusto de actualización pero la hipervelocidad se fue al traste jejeje ... tampoco es que me preocupe mucho porque no es algo que se haga cada día, pero siempre está bien mejorar.

Estudio vuestras opciones a ver si acelero la cosa :mrgreen: :mrgreen:

Angel Salom
Visionwin Software - https://www.visionwin.com
------------------------------------------------------------
fwh 19.05 - harbour 3.2 - bcc 7.4
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Copia de registros con FWH
Posted: Thu Jun 01, 2017 02:20 PM

Buenas

APPEND FROM , sería similar a los procesos Bulk de SQL Server, en un plis empujas todo ;-)

A veces , no queda más remedio que hacerlo de esta manera. En su día diseñe la aplicación de actualizaciones para la empresa, donde
se modifican/fusionan estructuras y se EMPUJA más de 3 gigas de datos.
El proceso tarda en algunas ocasiones más de una hora. Hacerlo uno a uno, es literalmente inviable.

En SQL, el intentar pasar datos haciendo INSERT, se demoraba más de 10 HORAS. Con un bulk, en un par de minutos.
A veces es necesario saber que volumen de datos estamos hablando para decantarse por una opción u otra.
De momento, tengo las 2 implementadas , por si acaso... :mrgreen:

Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
Re: Copia de registros con FWH
Posted: Sun Jun 11, 2017 12:53 AM
Faster solution would be to use
aData := SRC->( FW_DbfToArray( [cFieldList], [bFor] ) )
DST->( FW_ArrayToDBF( aData, [cFieldList] ) )

cFieldList in FW_DbfToArray() can be a list of expressions too.
FW_ArrayToDBF() does a reasonable conversion of values too.

It is possible to copy to DBF with different fieldnames and fieldtypes

Example:
Code (fw): Select all Collapse
aData := SRC->( FW_DbfToArray( "TRIM(FIRST)+','+TRIM(LAST),CITY,SALARY+2000", { || .NOT. FIELD->TRANSFER } ) )
DST->( FW_ArrayToDBF( aData, "CUSTNAME,CITY,AMOUNT" ) )


Even a lot faster is to use SQL. Here is an example assuming both tables are not having fpt memo fields.
Code (fw): Select all Collapse
#include "fivewin.ch"
function Main()

   local cFolder
   local oCn, oRs, cSql

   cFolder  := "c:\fwh\samples\"  // your path to fwh samples folder. Trailing \ is important
   DBCREATE( cFolder + "NEWTBL", { { "CUSTNAME", 'C', 60, 0 }, { "CITY", 'C', 30, 0 }, { "AMOUNT", 'N', 15, 2 } }, "DBFNTX" )

   oCn   := FW_OpenAdoConnection( cFolder )
   if oCn == nil
      ? "failed to connect"
   else
      ? "connection successful"
      cSql  := "INSERT INTO NEWTBL (CUSTNAME,CITY,AMOUNT) " + ;
               "SELECT TRIM(FIRST)+','+TRIM(LAST), CITY, SALARY+2000 FROM CUSTOMER WHERE AGE > 85"

      oCn:Execute( cSql )
      ocn:close()
   endif
   xbrowser cFolder + "NEWTBL.DBF"

return nil

Please build and try this sample. You will get the best speed.
Regards



G. N. Rao.

Hyderabad, India
Posts: 989
Joined: Thu Nov 24, 2005 03:01 PM
Re: Copia de registros con FWH
Posted: Mon Jun 12, 2017 07:38 AM
Tal y como dice Paquito, __dBTrans() es un misil. No hay comparación. Hice la siguiente prueba, intercalada entre código ya existente para aprovechar una tabla de las gordas y con muchos registros.

Code (fw): Select all Collapse
      
      dbCreate( 'Prueba', Creditos->( dbStruct() ) )
      USE Prueba NEW
      /* __dbTrans( nDstArea, aFieldsStru, bFor, bWhile, nNext, nRecord, lRest ) -> <lSuccess> */
      SELECT Creditos
      __dbTrans( Select( 'Prueba' ), /* { 'NCREDITO', 'CODORG', 'FECHACRED', 'FACTURA' }*/,,,, )
      CLOSE Prueba


En un Pentium Dual de 1.73 Ghz (un portatil de hace 10 años) con un disco SATA I de 500Gb traspasa 50K reg con 54 campos incluyendo memos en 2.58 segundos. Si limito la cantidad de campos a los 4 primeros, el tiempo baja a 1.31 segundos. Imbatible.

Como sucede con muchas funciones, hay poca documentación de __dBTrans() (¿O soy yo que no me entero?) pero rebuscando por ahí en algún mensaje de las listas de Harbour se explica que nDstArea debe ser el número de la WorkArea destino, aFieldsStru puede ser o bien un array con los nombres de los campos, pero tambien acepta arrays de estructura completa como los que devuelve dBStruct(). El resto de los parámetros son los mismos que en los comandos clásicos.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Copia de registros con FWH
Posted: Wed Jun 14, 2017 01:48 PM

Carlos
La velocidad es BRUTAL!!
Ahora bien, el problema que tengo es que cada vez que se ha procesado, debo de grabar en el origen que se ha procesado, y ahí radica el problema.
Si uso el bFor para cambiar el estado, lo hace, pero lo hace ANTES de pasar el registro al destino, entonces me encuentro el tener que
modificar un campo a posterior, he visto por ahí un __dbUpdate() a ver si ha posterior, procesar para cambiar el estado.

Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 817
Joined: Sun Jun 15, 2008 07:47 PM
Re: Copia de registros con FWH
Posted: Wed Jun 14, 2017 10:13 PM

Rafa no sé exactamente lo que haces... pero y en dos vueltas? uno para pasar y otro para marcar!!!

______________________________________________________________________________

Sevilla - Andalucía
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Copia de registros con FWH
Posted: Thu Jun 15, 2017 08:02 PM

Buenas Manuel , efictiviWOnder :mrgreen:

He estado enseñando a los compañeros Clipperianos , y no se lo creían ;-)

Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Copia de registros con FWH
Posted: Thu Jun 15, 2017 08:05 PM
Hi , thanks!
But the use __dbtrans () is BIG BIG BIG :-)

nageswaragunupudi wrote:
Please build and try this sample. You will get the best speed.
Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 989
Joined: Thu Nov 24, 2005 03:01 PM
Re: Copia de registros con FWH
Posted: Thu Jun 29, 2017 10:24 PM
thefull wrote:Carlos
La velocidad es BRUTAL!!
Ahora bien, el problema que tengo es que cada vez que se ha procesado, debo de grabar en el origen que se ha procesado, y ahí radica el problema.
Si uso el bFor para cambiar el estado, lo hace, pero lo hace ANTES de pasar el registro al destino, entonces me encuentro el tener que
modificar un campo a posterior, he visto por ahí un __dbUpdate() a ver si ha posterior, procesar para cambiar el estado.


Pregunta: Ese campo donde grabas si se actualizó... ¿Que guarda? ¿Booleano? Tal vez se pueda usar la lista de todos los campos excepto ese de estado, con lo que no se actualizaría.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"

Continue the discussion