Como encontrar una cadena en todos los reg de una o mas DBFs

Como encontrar una cadena en todos los reg de una o mas DBFs

Postby FranciscoA » Sun Aug 17, 2008 8:18 pm

Navegando por este foro el dia de hoy, encontré a dos usuarios que buscaban solución a como encontrar y mostrar un dato en todos los registros de una o más DBFs. (incluso en todos los SubDir que se deseen, con una minima modificación)

Picado por la curiosidad y las ganas de ejercitarme un poco, procedí a crear las siguientes funciones que espero les sean de mucha utilidad para integrar sus propias busquedas.

Cualquier mejora es bienvenida.

Saludos.

Francisco J. Alegría P.
Chinandega, Nicaragua.


/* Ejemplo de busqueda en todos los campos de las DBFs deseadas o en un subdirectorio
segun el tipo de dato requerido. (caracter,numerico o fecha)
Se muestran los resultados con la funcion MsgList(), pero bien pueden re-dirigirse
a una dbf u otro tipo de destino.
Muestra, en MsgList(), el nombre de la DBF, el nombre del campo, el No. de registro y el valor buscado.
Se puede mejorar agregando la busqueda en un campo específico.
Si se utiliza un array con las DBFs definidas y no encuentra alguna, informa al respecto.
*/

//Francisco J. Alegría P. :Me gustaría recibir sus mejoras. Saludos. ( falegria230349@yahoo.es )
//Chinandega, Nicaragua.
//Agosto 17/2008


#include "FiveWin.ch"
**#include "directry.ch" //por si se usa aDirectory()

static aEncont:={}
//-------------------------------------------//
function Main()
local oDlg, xBuscar, oBuscar, oRadio, nVar:=1

SET DATE BRITISH
SET EPOCH TO 1995
SET CENTURY ON
SET DELETED ON

set resources to "busqueda.dll"

DEFINE DIALOG oDlg RESOURCE "BUSCADOR1" TITLE "Prueba de busqueda de un valor en DBFs"

REDEFINE RADIO oRadio VAR nVar ID 103,104,105 OF oDlg ON CHANGE Refresque(@xBuscar,oBuscar,nVar)

REDEFINE GET oBuscar VAR xBuscar ID 102 OF oDlg

REDEFINE BUTTON ID 201 OF oDlg Action ( if(!empty(xBuscar),MsgRun("Aguarde...",,{||Busque(xBuscar)}), msgStop("Valor omitido")),oBuscar:SetFocus() )
REDEFINE BUTTON ID 202 OF oDlg Action ( oDlg:end() ) CANCEL

ACTIVATE DIALOG oDlg CENTERED

return nil

//------------------------
Function Refresque(xBuscar,oBuscar,nVar)
if nVar=1
xBuscar:=space(20)
elseif nVar=2
xBuscar:=0.0000
elseif nVar=3
xBuscar:=date()
endif
oBuscar:Refresh()
Return nil

//---------------------------
//debe usarse aDirectory() si se desea busqueda en todas las DBFs del subdir.
//---------------------------
Function Busque(xBuscar)
local cTipoDato:=ValType(xBuscar)
local aDBFS:={"test","wmdata"}
local n:=0, cAlias
local TpoIn:=Seconds(), TpoFi:=0, nRegist:=0, nDbfs:=0, nReg:=0

For n:=1 to len(aDBFS)
if !file(aDBFS[n]+".dbf")
aadd(aEncont,"NO SE ENCONTRO "+aDBFS[n]+".dbf")
else
dbUseArea(.t.,,aDBFS[n],aDBFS[n],.t.)
nRegist+=(aDBFS[n])->(Reccount())
nDbfs+=1
Buscando(aDBFS[n],xBuscar,cTipoDato,@nReg)
(aDBFS[n])->(dbCloseArea())
endif
Next

MsgInfo("Total Segundos "+transform(Seconds()-TpoIn,"999,999.99")+chr(13)+;
"Bases de datos escaneadas "+alltrim(str(nDbfs))+chr(13)+;
"Registros encontrados "+transform(nReg,"9,999,999"), transform(nRegist,"9,999,999")+" reg. escaneados")

SysRefresh()

if !empty(aEncont)
MsgList(aEncont, "Registros encontrados",1,1,30,80,"Salir")
else
MsgInfo("No se encontraron coincidencias")
endif
aEncont:={}
Return nil


//------------------------
Function Buscando(cAlias,xBuscar,cTipoDato,nReg)
local n:=0

(cAlias)->(dbgotop())

WHILE (cAlias)->(!eof())
for n:=1 to (cAlias)->(fCount())
if ValType( (cAlias)->(FieldGet(n)) ) == cTipoDato
if cTipoDato = "C"
xBuscar:=Upper(alltrim(xBuscar)) //convertimos a mayusc para asegurar resultado
if At( xBuscar, Upper((cAlias)->(FieldGet(n))) ) != 0 //si encuentra coincidencia
aadd( aEncont, (cAlias)+"->"+(cAlias)->(FieldName(n)) +" (Reg "+Alltrim(str((cAlias)->(Recno()))) +") "+(cAlias)->(FieldGet(n)) ) //lo agregamos a un array
nReg+=1
endif
elseif cTipoDato = "N"
if (cAlias)->(FieldGet(n)) = xBuscar
aadd( aEncont, (cAlias)+"->"+(cAlias)->(FieldName(n)) +" (Reg "+Alltrim(str((cAlias)->(Recno()))) +") "+Transform((cAlias)->(FieldGet(n)),"999,999,999.9999") )
nReg+=1
endif
elseif cTipoDato = "D"
if (cAlias)->(FieldGet(n)) = xBuscar
aadd( aEncont, (cAlias)+"->"+(cAlias)->(FieldName(n)) +" (Reg "+Alltrim(str((cAlias)->(Recno()))) +") "+Dtoc((cAlias)->(FieldGet(n))) )
nReg+=1
endif
endif
endif
next
SysRefresh()
(cAlias)->(dbSkip())
ENDDO

Return nil
Last edited by FranciscoA on Mon Aug 18, 2008 4:09 pm, edited 1 time in total.
User avatar
FranciscoA
 
Posts: 2110
Joined: Fri Jul 18, 2008 1:24 am
Location: Chinandega, Nicaragua, C.A.

Postby Antonio Linares » Mon Aug 18, 2008 1:29 am

FieldGet() y DbSkip() son muchísimo más lentos que usar At() directamente en toda la DBF cargada en memoria.

Al usar At() nos saltamos todo el mecanismo interno de los RDDs y usamos el sistema de búsqueda más rápido que puede hacerse en un bloque de datos.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Postby FranciscoA » Mon Aug 18, 2008 1:25 pm

Antonio Linares wrote:FieldGet() y DbSkip() son muchísimo más lentos que usar At() directamente en toda la DBF cargada en memoria.

Al usar At() nos saltamos todo el mecanismo interno de los RDDs y usamos el sistema de búsqueda más rápido que puede hacerse en un bloque de datos.


Gracias, Antonio.
Saludos.
User avatar
FranciscoA
 
Posts: 2110
Joined: Fri Jul 18, 2008 1:24 am
Location: Chinandega, Nicaragua, C.A.

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby Silvio.Falconi » Sun Nov 30, 2014 5:25 pm

Can I see a sample test of it ?
I need a search of a word or some words into a field memo or character ...
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 6772
Joined: Thu Oct 18, 2012 7:17 pm

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby Antonio Linares » Sun Nov 30, 2014 6:16 pm

MsgInfo( At( "Silvio", MemoRead( "MyDbf.dbf" ) ) )
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby Silvio.Falconi » Tue Dec 02, 2014 8:35 am

Antonio,

I wish insert all Whats new of Fwh into a Dbf

DbCreate(cDir+'FW', {{ "FWANYO" , "C", 4, 0 },; // sample 2014
{ "FWNUMERO" , "C", 2, 0 },; // sample 09
{ "FWWHATS", "C", 250, 0 } } , 'DBFCDX')

AND INSERT ON FWWHATS FIELD THE WHATS NEW COMMENT

Now I wish search a word or a sentence into FWWHATS field and the function must give me ( show on screen)
the year and release and the text where the procedure found the sentence or the word i insert to find.
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 6772
Joined: Thu Oct 18, 2012 7:17 pm

Re:

Postby cnavarro » Wed Dec 03, 2014 7:55 pm

Antonio Linares wrote:FieldGet() y DbSkip() son muchísimo más lentos que usar At() directamente en toda la DBF cargada en memoria.

Al usar At() nos saltamos todo el mecanismo interno de los RDDs y usamos el sistema de búsqueda más rápido que puede hacerse en un bloque de datos.


Antonio, sin que sea exactamente el tema que se describe aqui, qué es más rápido?

Code: Select all  Expand view

if cSearch $ cString
...
 


o

Code: Select all  Expand view

if !empty( At( cSearch, cString ) )
...
 
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6500
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby hmpaquito » Wed Dec 03, 2014 10:23 pm

Cristobal,

Yo no lo sé pero de entrada se me antoja que At(cSearch, cString) == 0 sea levísimamente mas rapido que Empty( At(cSearch, cString) )

Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby FiveWiDi » Fri Dec 05, 2014 8:54 pm

Hola todos,

No es la solución a lo que mencionan, pero tiene algo que ver y además puede servir para desarrollar lo que se desea.
Imagínense una DBF enorme en la cual deben buscar un valor en un campo el cual no está indexado; pués para este caso les serviría este código:

Por cierto, si alguien crea una clase con ello, pues mejor que mejor; así se podrá utilizar para diversas DBF a la vez.

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.
   Devuelve -1 cuando el campo indicado no existe en la DBF o no se especifica 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 -1
    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 -1
    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

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby Antonio Linares » Sat Dec 06, 2014 7:22 am

Cristobal,

Supongo que lo más rápido es

if cSearch $ cString

pero no habrá mucha diferencia entre las dos formas que muestras
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby hmpaquito » Mon Dec 08, 2014 8:22 pm

Gracias Fivewidi por tu clase... tiene una pinta sensacional... me la guardo para cuando la necesite...
Una funcion asi siempre la quise tener.

Por cierto... una pregunta... ¿ has hecho pruebas tomando tiempos ? ¿ va bien de velocidad ?

Un saludo y de nuevo gracias por el aporte.
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby elvira » Tue Dec 09, 2014 7:11 am

Fivewidi , muy agradecida!!!.

Una dudita, ¿funciona cuando se abre la dbf en modo SHARED??.
elvira
 
Posts: 515
Joined: Fri Jun 29, 2012 12:49 pm

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby FiveWiDi » Tue Dec 09, 2014 7:25 am

hmpaquito wrote:Gracias Fivewidi por tu clase... tiene una pinta sensacional... me la guardo para cuando la necesite...
Una funcion asi siempre la quise tener.

Por cierto... una pregunta... ¿ has hecho pruebas tomando tiempos ? ¿ va bien de velocidad ?


No es una clase, no estoy familiarizado en crear clases y esta función la cree para jugar un poco con el código; y si alguién lo quiere convertir en una clase sería de agradecer.
Respecto a la velocidad, pués no tengo ninguna DBF grande para provar, pero tratándose de substiturir un locate y con los comentarios de antonio respecto al uso de AT(), creo que debe mejorarla.

Saludos,
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

Re: Como encontrar una cadena en todos los reg de una o mas DBFs

Postby FiveWiDi » Tue Dec 09, 2014 7:26 am

elvira wrote:Fivewidi , muy agradecida!!!.

Una dudita, ¿funciona cuando se abre la dbf en modo SHARED??.

Debería funcionar sin problemas y creo que así lo probé en su día.

Saludos,
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 FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 78 guests