Búsqueda rápida en DBF enorme?

Post Reply
FiveWiDi
Posts: 910
Joined: Mon Oct 10, 2005 2:38 pm

Búsqueda rápida en DBF enorme?

Post by FiveWiDi »

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

#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 19.06 + Harbour 3.2, BCC 7 Windows 10
Post Reply