Búsqueda rápida en DBF enorme?

Búsqueda rápida en DBF enorme?

Postby FiveWiDi » Wed May 13, 2009 6:31 pm

Hola a todos,

Aquí les dejo una función que he estado haciendo estos días (tenía tiempo).

La finalidad es la búsqueda de un valor dentro de una DBF mediante la función At().

Creo que sólo será útil para ficheros enormes; para los más pequeños las funciones de Harbour ya nos valen.

Agradecería que alguién que tenga algún fichero DBF enorme la pruebe y nos diga si és más rápido que con el comando LOCATE.
Yo no puedo hacerlo, no dispongo de ficheros enormes (ni tampoco espacio en el disco, je, je).

Un Saludo y gracias
Carlos G.

Code: Select all  Expand view

#include "fivewin.ch"
#include "Dbstruct.ch"
#include "DbInfo.ch"

/* Función para buscar en una DBF (en su orden NATURAL) un valor contenido
   en un campo determinado.
   Simula el comando LOCATE y CONTINUE, pero realizando un AT().
   Devuelve el Recno() ó '0' según encuentre o no el valor a buscar.
   Se asume que la DBF está abierta y se recibe su Alias().

   Su uso es:
   nAtInDbf( cAliasDBF, "APELLIDO", "GARCIA", .F. )

   para continuar la búsqueda con los mismos parámetros:
   nAtInDbf( cAliasDBF, , , .T. )

   Para que nos entendamos, la primera vez vendría a ser un LOCATE, y la segunda
   vez vendría a ser un CONTINUE.

   --------------------------------------------------------------------------------- */


FUNCTION nAtInDbf( cAliasDBF, cFieldDBF, cString, lContinue )

STATIC cMemoDbf       := "", ;
       nBytesToField  := 0, ;
       nBytesEndField := 0, ;
       nOffset        := 0, ;
       cSearch        := "", ;
       cfield         := "", ;
       nRegLocate_1   := 0

Local aEstruct     := {}
Local nPos         := 0

DEFAULT lContinue := .F.

/*
Traza( 1, cAliasDbf )
Traza( 1, ( cAliasDbf )->(DbInfo( DBI_FULLPATH )) )
Traza( 1, cFieldDbf )
Traza( 1, cString )
Traza( 1, lContinue )
*/


If .not. lContinue
    If Len( cString ) < 1
        MsgInfo("Not Data to Search.", "Search Error." )
        Return 0
    Endif
    cMemoDbf       := MemoRead( ( cAliasDbf )->(DbInfo( DBI_FULLPATH )) )
    nOffset        := 0
    cSearch        := cString
    cField         := Upper( cfieldDBF )
    nRegLocate_1   := 0

    nBytesToField  := 0
    nBytesEndField := 0

    aEstruct       := ( cAliasDBF )->(DBSTRUCT())
    AScan( aEstruct, { |aCampo| If( aCampo[ DBS_NAME ] == cField, ;
                                    (nBytesEndField := nBytesToField + aCampo[ DBS_LEN ] + aCampo[ DBS_DEC ], .T.), ;
                                    (nBytesToField := nBytesToField + aCampo[ DBS_LEN ] + aCampo[ DBS_DEC ], .F. ) ;
                                  ) ;
                     } ;
         )

    If nBytesEndField = 0
        MsgInfo("Field not found.", "Search Error." )
        Return 0
    Endif

EndIf

nPos := 0
While nPos <= ( ( cAliasDBF )->(Header()) + (nRegLocate_1 * ( cAliasDBF )->(RecSize()) ) + nBytesToField) .or. ;
      nPos > ( ( cAliasDBF )->(Header()) + (nRegLocate_1 * ( cAliasDBF )->(RecSize()) ) + nBytesEndField)

    nPos      := AT( cSearch, SubStr(cMemoDbf, nOffset + 1) )

    If nPos = 0
        nRegLocate_1 = -1
        Exit
    EndIf

    nOffset := nPos := nPos + nOffSet

    nRegLocate_1 := INT( ( nPos - ( cAliasDBF )->(Header()) ) / ( cAliasDBF )->(RecSize()) ) // Registro anterior al localizado¿?

    If (( nPos - ( cAliasDBF )->(Header()) ) % ( cAliasDBF )->(RecSize())) = 0
        nRegLocate_1 = nRegLocate_1 - 1  // Registro anterior al localizado.
    EndIf

End

Return nRegLocate_1 + 1
//------------------------------------------------------------------
 
Un Saludo
Carlos G.

FiveWin 24.02 + Harbour 3.2.0dev (r2403071241), BCC 7.7 Windows 10
FiveWiDi
 
Posts: 1060
Joined: Mon Oct 10, 2005 2:38 pm

Return to Utilities / Utilidades

Who is online

Users browsing this forum: No registered users and 4 guests