Leer archivo Excel / lectura lenta

HMG en Español

Moderator: Rathinagiri

jparada
Posts: 433
Joined: Fri Jan 23, 2009 5:18 pm

Re: Leer archivo Excel / lectura lenta

Post by jparada »

Hola amigos,
Con el cambio que me comentan al parecer está funcionando el obtener los datos correctamente, pero ahora la duda por qué se se detiene después de leer las primeras 4 filas.
img.png
img.png (47.8 KiB) Viewed 3460 times
Éste es el código hasta el momento:

Code: Select all

#include "hmg.ch"

#xcommand TRY  => BEGIN SEQUENCE WITH {| oErr | Break( oErr ) }
#xcommand CATCH [<!oErr!>] => RECOVER [USING <oErr>] <-oErr->
#xcommand FINALLY => ALWAYS

FUNCTION Main()  
  LOCAL lastRow
  LOCAL oErr, oErrRS
  LOCAL oCnn, oRs
  LOCAL oExcel, cQry
  LOCAL oWorkBook, oHoja, nFilas
  LOCAL i
  LOCAL codigo, descripcion, costo, precio  
  LOCAL cTime :=  Time()
  LOCAL numRows
  LOCAL numColumns
  LOCAL aExcel := {}
  LOCAL cEnde
  LOCAL nRow
  LOCAL j
  
  IF ( oCnn := win_OleCreateObject( "ADODB.Connection" ) ) == NIL
    ? 'No es posible crear objeto conexión, ' + win_OleErrorText()
    RETURN NIL
  ENDIF

  TRY    
    oCnn:Open( "Provider=SQLNCLI11;Server=JPARADA\COMPAC;Database=adMI_EMPRESA;Uid=sa;Pwd=sapito;" )
  CATCH oErr
    ? "Error al intentar conectar a la base de datos " +  e"\n" + hb_StrToUtf8(oErr:Description)
    RETURN NIL
  END

  //aquí RecordSet
  //oRs := win_OleCreateObject( "ADODB.Recordset" )
  //

  IF ( oExcel := win_oleCreateObject( "Excel.Application" ) ) == NIL
    ? 'Error: Microsoft Excel no está disponible, ', win_OleErrorText()
    RETURN NIL
  ENDIF
    
  oExcel:Visible := .F.  
  oExcel:Application:DisplayAlerts := .F.  
  oExcel:Application:Workbooks:open( "C:\desarrollo_hmg\actualizar_precios_hmg\lista_precios_2020.xlsx" )
  oWorkBook := oExcel:activeWorkBook
  oExcel:Application:Worksheets(1):activate()  
  oSheet := oExcel:Worksheets(1):cells
  
  //oWorkBook:WorkSheets(1):usedRange:Select    // ***** ERROR ***** //
  //numRows    := oWorkBook:workSheets(1):usedRange:Rows:Count
  //numColumns := oWorkBook:workSheets(1):usedRange:Columns:Count

  numRows := 2091
  numColumns := 4

  FOR i := 1 TO numRows
    AADD( aExcel, Array(numColumns) )
  NEXT

  cEnde := DataToChr(numColumns)  
  aExcel := oSheet:Range( "A2:"+cEnde+LTrim(Str(numRows)) ):Value  

  //? ValtoPrg( aExcel )
  
  FOR j:=1 TO Len(aExcel)
    codigo      := aExcel [1][j]
    descripcion := aExcel [2][j]
    costo       := aExcel [3][j]    
    precio      := aExcel [4][j]



    ? 'Registro ' + Alltrim( Str(j) ) 
    ? hb_utf8ToStr('Código: ') + codigo 
    ? hb_utf8ToStr('Descripción: ') + descripcion
    ? 'Costo: ' + str(costo)
    ? 'Precio: ' + str(precio)


    cQry := "UPDATE admProductos SET " + ;
    "cprecio1 = " + DataToSQL(precio) + ", " + ;
    "cprecio2 = " + DataToSQL(precio) + ", " + ;
    "cprecio3 = " + DataToSQL(precio) + ", " + ;
    "cprecio4 = " + DataToSQL(precio) + ", " + ;
    "cprecio5 = " + DataToSQL(costo) + ", " + ;
    "cprecio6 = " + DataToSQL(precio) + ", " + ;
    "cprecio7 = " + DataToSQL(precio) + ", " + ;
    "cprecio8 = " + DataToSQL(precio) + ", " + ;
    "cprecio9 = " + DataToSQL(precio) + ", " + ;
    "cprecio10 = " + DataToSQL(precio) + " " + "WHERE ccodigoproducto = " + DataToSQL(codigo)
    
    //MsgInfo( cQry )
    QOut( cQry )
    //?
    //?
    //HB_TimeSleep( 0.10 )



  /*
    TRY
      oCnn:Execute( cQry )
    CATCH oErrRS
      ? "Error al actualizar datos en la tabla" +  e"\n" + hb_StrToUtf8(oErrRS:Description)
      RETURN .F.
    END
    */

  NEXT
  
  
  oExcel:Quit()
  
    
  ?
  ? "Todo OK, Tiempo transcurrido : " + ElapTime( cTime, time() )
  ?

  //cerrar conexión y recordset (si es que utilizamos RecordSet)
  oCnn:Close()
  oCnn := NIL

  // RecordSet
  //oRS:Close()
  //oRS := NIL

RETURN NIL
/*******/
Gracias por su ayuda.

Saludos,
Javier
Tiger
Posts: 74
Joined: Mon Aug 31, 2015 11:28 am
Location: Taipei

Re: Leer archivo Excel / lectura lenta

Post by Tiger »

Please check following codes ….
oExcel:Workbooks:open( "C: \ development_hmg \ update_prices_hmg \ price_list_2020.xlsx")
oSheet:=oExcel:ActiveSheet()
numRows:=oSheet:UsedRange:Rows:Count()
numColumns:=oSheet:UsedRange:Columns:Count()

It works for me … but I have a problem to trim the space when use the array ...
G_COUS:=ALLTRIM(Cell2CHR(aExcel[1,4])) … it seems the alltrim() function is not work to trim the space
User avatar
andyglezl
Posts: 1461
Joined: Fri Oct 26, 2012 7:58 pm
Location: Guadalajara Jalisco, MX
Contact:

Re: Leer archivo Excel / lectura lenta

Post by andyglezl »

Como no lo podemos probar... Quizá...
*-----------------------------------------------
As we can't prove it ... Maybe ...



numColumns := 4
.....
.....
cEnde := DataToChr( numColumns )
Andrés González López
Desde Guadalajara, Jalisco. México.
jparada
Posts: 433
Joined: Fri Jan 23, 2009 5:18 pm

Re: Leer archivo Excel / lectura lenta

Post by jparada »

Hola,
Adjunto los archivos a ver si pueden probar y ayudar con la solución, o tal vez plantear una solución diferente, recordemos que empecé a probar esto del array por la recomendación de auge_ohr (con todo respecto, no sé su nombre) para leer el contenido de Excel por mi problema original de lectura muy lenta.
excel.zip
(213.78 KiB) Downloaded 208 times
Gracias por la ayuda.

Saludos,
Javier
User avatar
AUGE_OHR
Posts: 2117
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany

Re: Leer archivo Excel / lectura lenta

Post by AUGE_OHR »

hi,

my Name is Jimmy

you Code is for M$-Server but i have only PostgreSQL and MySQL so i can't Check you Code.

Code: Select all

numRows := 2091
cEnde := DataToChr(numColumns) 
i never have try so big Number ... use Debugger to check what is in cEnde

Code: Select all

  FOR j:=1 TO Len(aExcel)
    codigo      := aExcel [1][j]
    descripcion := aExcel [2][j]
    costo       := aExcel [3][j]    
    precio      := aExcel [4][j]
em, äh ... IHMO it must be

Code: Select all

  FOR j:=1 TO Len(aExcel)
    codigo      := aExcel [j][1]
    descripcion := aExcel [j][2]
    costo       := aExcel [j][3] 
    precio      := aExcel [j][4]
have a look at this Sample

Code: Select all

#include "Directry.ch" 
PROCEDURE Main 
LOCAL aDbfFiles := Directory("*.DBF") 
LOCAL nCount    := Len(aDbfFiles) 
LOCAL n, nSum := 0 
 
   FOR n:= 1 TO nCount 
       nSum += aDbfFiles[ n, F_SIZE ] 
   NEXT 
    ? nCount, "DBF-Dateien belegen", nSum, "Bytes" 
RETURN 
have fun
Jimmy
have fun
Jimmy
jparada
Posts: 433
Joined: Fri Jan 23, 2009 5:18 pm

Re: Leer archivo Excel / lectura lenta

Post by jparada »

;) Este post se volvió un poco el teléfono descompuesto como el chavo, quico y la chilindrina :lol:
User avatar
andyglezl
Posts: 1461
Joined: Fri Oct 26, 2012 7:58 pm
Location: Guadalajara Jalisco, MX
Contact:

Re: Leer archivo Excel / lectura lenta

Post by andyglezl »

Veo que este tema ya se había tratado antes...

Pregunta: Necesariamente tienes que leer todo el archivo con EXCEL ?
(lo digo por lo que se comentó anteriormente, de que las diferente versiones, hacen cosas diferentes)

La opción que yo sugerí en ese momento es lo mismo que ahora con el Array, solo que con un DBF
(Teniendo el DBF, lo puedes leer y grabar donde quieras.)
*---------------------------------------------------------------------------------------------------------------------------
I see that this issue had been discussed before ...

Question: Do you necessarily have to read the entire file with EXCEL?
(I say this because of what was said before, that different versions do different things)

The option that I suggested at that time is the same as now with the Array, only with a DBF
(Having the DBF, you can read and record it wherever you want.)


https://www.hmgforum.com/viewtopic.php? ... m&start=10
Last edited by andyglezl on Mon Dec 23, 2019 4:20 pm, edited 1 time in total.
Andrés González López
Desde Guadalajara, Jalisco. México.
jparada
Posts: 433
Joined: Fri Jan 23, 2009 5:18 pm

Re: Leer archivo Excel / lectura lenta

Post by jparada »

Hola Andrés,
Se debe leer todo el archivo ya que es la lista de precios actualizados para 2020, no me gusta la idea de pasar por dbf, además que tiene rato que ya no utilizo dbfs, si tienes tiempo prueba por favor con las dos opciones, la primer opción que comento de la lectura lenta, es parecido a lo que tu mencionas, ya que creo recordar de ahí tomé el ejemplo y la segunda con el tema del array: no es necesario nada de base de datos, sólo para probar la lectura, si me puedes apoyar por favor haciendo la prueba te lo agradezco.

Saludos,
Javier
jparada
Posts: 433
Joined: Fri Jan 23, 2009 5:18 pm

Re: Leer archivo Excel / lectura lenta

Post by jparada »

Hola,
Éste código ha funcionado bien, incluso leyendo un archivo Excel +8000 filas el tiempo de lectura y actualización de datos es de 3 minutos, creo yo más que aceptable.

Incluso enviando a dbf el contenido la respuesta es igual de rápida, en el post sugerido por Andrés está la función de conversión de datos de @Marek

Code: Select all

#include "hmg.ch"

#xcommand TRY  => BEGIN SEQUENCE WITH {| oErr | Break( oErr ) }
#xcommand CATCH [<!oErr!>] => RECOVER [USING <oErr>] <-oErr->
#xcommand FINALLY => ALWAYS

/*
* Main
*/
PROCEDURE MAIN()
  LOCAL oExcel, oSheet
  LOCAL nTotalRows, nRows
  LOCAL xField
  LOCAL cTime :=  Time()
  LOCAL oErr, oErrRS
  LOCAL oCnn, oRs
  LOCAL cQry

  IF ( oCnn := win_OleCreateObject( "ADODB.Connection" ) ) == NIL
    MsgBox( "No es posible crear objeto conexión: " + hb_Utf8ToStr(win_OleErrorText()) )
    RETURN NIL
  ENDIF

  TRY    
    oCnn:Open( "Provider=SQLNCLI11;Server=Server;Database=Database;Uid=User;Pwd=Pwd;" )
  CATCH oErr
    MsgBox( "Error al intentar conectar a la base de datos " +  e"\n" + hb_Utf8ToStr(oErr:Description) )
    RETURN NIL
  END

  oExcel := CreateObject( "Excel.Application")

  oExcel:Workbooks:Open( GetCurrentFolder()+"\lista.xlsx" ) 
  oExcel:WorkSheets("Precios"):Select()
  oSheet := oExcel:ActiveSheet

  nTotalRows    := oExcel:WorkSheets("Precios"):usedRange:Rows:Count()
   
  //MsgBox(oSheet:name)
  //MsgBox(nTotalRows)

  //USE test NEW EXCLUSIVE
  //ZAP    
  
  nRows := 2  
  DO WHILE nRows <= nTotalRows  
    //Select("test")
	  //Append Blank
    /*
    Replace codigo	With Alltrim( ConvertData(oSheet:Cells( nRows, 1 ):Value) ), ;
            nombre	With Alltrim( ConvertData(oSheet:Cells( nRows, 2 ):Value) ), ;
            costo	  With IF( ValType(xField := oSheet:Cells( nRows, 3 ):Value) == "N", xField, 0), ;
            precio  With IF( ValType(xField := oSheet:Cells( nRows, 4 ):Value) == "N", xField, 0)
    */


    codigo	:= Alltrim( ConvertData(oSheet:Cells( nRows, 1 ):Value) )
    nombre	:= Alltrim( ConvertData(oSheet:Cells( nRows, 2 ):Value) )
    costo	  := IF( ValType(xField := oSheet:Cells( nRows, 3 ):Value) == "N", xField, 0)
    precio  := IF( ValType(xField := oSheet:Cells( nRows, 4 ):Value) == "N", xField, 0)

    cQry := "UPDATE admProductos SET " + ;
            "cprecio1 = " + DataToSQL(precio) + ", " + ;
            "cprecio2 = " + DataToSQL(precio) + ", " + ;
            "cprecio3 = " + DataToSQL(precio) + ", " + ;
            "cprecio4 = " + DataToSQL(precio) + ", " + ;
            "cprecio5 = " + DataToSQL(costo) + ", " + ;
            "cprecio6 = " + DataToSQL(precio) + ", " + ;
            "cprecio7 = " + DataToSQL(precio) + ", " + ;
            "cprecio8 = " + DataToSQL(precio) + ", " + ;
            "cprecio9 = " + DataToSQL(precio) + ", " + ;
            "cprecio10 = " + DataToSQL(precio) + " " + "WHERE ccodigoproducto = " + DataToSQL(codigo)
            
    //MsgBox( cQry )
    QOut( cQry )
            
    TRY
      oCnn:Execute( cQry )
    CATCH oErrRS              
      MsgBox( "Error al actualizar datos en la tabla" +  e"\n" + hb_Utf8ToStr(oErrRS:Description) )
      RETURN .F.
    END
		nRows ++
  ENDDO
  
  oExcel:Visible := .T.
  MsgBox( "Proceso terminado, tiempo transcurrido: " + ElapTime( cTime, Time() ) )

	//USE
  oExcel := NIL
  
  //cerrar conexión y recordset (si es que utilizamos RecordSet)
  oCnn:Close()
  oCnn := NIL  

RETURN NIL
/*******/


/*
* ConvertData
*/
FUNCTION ConvertData()
  PARAM	xValue
	LOCAL ret
	
	IF Type("xValue") == "D"
		ret := DTOC(xValue)
	ELSEIF Type("xValue") == "N"
		ret := Str(xValue)
	ELSEIF Type("xValue") == "L"
		ret := IF(xValue,"True","False")
  ELSEIF Type("xValue") = "C"
		ret := xValue
  ELSE
		ret := ""
  ENDIF

RETURN ret
 /*******/

 /*
* DataToSQL
*/
FUNCTION DataToSQL( xField )
  LOCAL cType, result := 'NULL'
  
  cType := ValType( xField )
  
  IF cType == "C" .OR. cType == "M"
    IF !Empty( xField ) 
      result := "'" + Alltrim(xField) + "'"
      //result := Alltrim(result)
    ENDIF
    
    IF xField == "NIL"
      result := 'NULL'
    ENDIF

  ELSEIF cType == "D" .AND. !Empty( xField )
    // formato fecha ISO 8601 YYYYMMDD
    result := "'" + StrZero( Year( xField ), 4 )
    result += StrZero( Month( xField ), 2 )
    result += StrZero( Day( xField ), 2 ) + "'"

  ELSEIF cType == "N"
    result := hb_Ntos( xField )
    result := "'" + result + "'"

  ELSEIF cType == "L"
    result := IIF( xField, "'t'", "'f'" )
  ENDIF

RETURN result
/*******/
Gracias a todos por su ayuda.

Saludos,
Javier
Tiger
Posts: 74
Joined: Mon Aug 31, 2015 11:28 am
Location: Taipei

Re: Leer archivo Excel / lectura lenta

Post by Tiger »

Could you please try to add following codes to you program to check if any help on the "speed" ???

oExcel:=CreateObject("Excel.Application")

oExcel:ScreenUpdating:=.F.
oExcel:EnableEvents:=.F.
oExcel:EnableAnimations:=.F.

and

codigo := Alltrim( ConvertData(oSheet:Cells( nRows, 1 ):Value2) )
nombre := Alltrim( ConvertData(oSheet:Cells( nRows, 2 ):Value2) )
costo := IF( ValType(xField := oSheet:Cells( nRows, 3 ):Value2) == "N", xField, 0)
precio := IF( ValType(xField := oSheet:Cells( nRows, 4 ):Value2) == "N", xField, 0)

.
.
.
.

oExcel:Visible := .T.
oExcel:ScreenUpdating:=.T.
oExcel:EnableEvents:=.T.
oExcel:EnableAnimations:=.T.
Post Reply