FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Ayuda Dbsetfilter anidado
Posts: 350
Joined: Wed Nov 02, 2005 03:28 PM
Ayuda Dbsetfilter anidado
Posted: Tue Oct 04, 2011 06:00 PM
Quiero filtrar una base de datos con distintas caracteristicas, si lo hago solo funciona correctamente el problema es cuando lo "anido" que no hace ning煤n filtro, os dejo el codigo por si podeis echarme una mano.
Gracias
Code (fw): Select all Collapse
static function filtrararticulo(aVars)
聽 聽 if Var(1) <= 1 .and. Var(2) <= 1 .and. Var(3) <= 1 .and.;
聽 聽 聽 聽Var(4) <= 1 .and. Var(5) <= 1 .and. Var(5) <= 1
聽 聽 聽 聽msgalert("Debe seleccionar al menos una caracteristica del Articulo.")
聽 聽 聽 聽return ""
聽 聽 endif
聽 聽 (carticulo) ->( dbClearFilter(NIL) )
聽 聽 cfiltro:=""
聽 聽 IF Var(1) > 1
聽 聽 聽 * (carticulo)->(DbSetFilter(;
聽 聽 聽 * 聽 聽 聽 聽 聽 聽 聽 聽 聽{ || (carticulo)->ancho=val(tancho[Var(1)]) },;
聽 聽 聽 * 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽"(carticulo)->ancho=val(tancho[Var(1)])"))
聽 聽 聽 cfiltro:=cfiltro+'"(carticulo)->ancho=val(tancho[Var(1)])"'
聽 聽 endif
聽 聽 IF Var(2) > 1
聽 聽 聽* (carticulo)->(DbSetFilter(;
聽 聽 聽* 聽 聽 聽 聽 聽 聽 聽 聽 聽 { || (carticulo)->densidad=(tdensidad[Var(2)]) },;
聽 聽 聽* 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 "(carticulo)->densidad=(tdensidad[Var(2)])"))
聽 聽 聽 if !empty(cfiltro)
聽 聽 聽 聽 聽cfiltro:=cfiltro+'" .and. "'
聽 聽 聽 endif
聽 聽 聽 cfiltro:=cfiltro+'" (carticulo)->densidad=(tdensidad[Var(2)]) "'
聽 聽 endif

聽 聽 聽 聽(carticulo)->(DbSetFilter( {|| &cfiltro }, cfiltro ) )
聽 聽 聽 聽(carticulo)->(dbgotop())

return nil
Saludos,
Regards,

Jose Luis Alepuz
joseluis@mancomputer.com
www.mancomputer.com
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Ayuda Dbsetfilter anidado
Posted: Tue Oct 04, 2011 06:18 PM
Amigo Garbi,

驴 Qu茅 quieres, dos anidamientos, doscientos o dos mil ? Los que quieras :-)

Mira el ejemplo:
Code (fw): Select all Collapse
FUNCTION Sample()
Local bFil1:= {|| .t. },;
         bFil2:= {|| .t.},;
         bFil3:= {|| .t.},;
         bFil4:= {|| .t.}
IF ...
   bFil1:= {|| lCon1}
ENDIF
IF ...
  bFil2:= {|| lCon2 }
ENDIF
IF ...
   bFil3:= {|| lCon3 }
ENDIF
IF ...
   bFil4:= {|| lCon4}
ENDIF
SELECT (cAli)
SET FILTER TO Eval(bFil1) .AND. Eval(bFil2) .AND. Eval(bFil3) .AND. Eval(bFil4)
RETURN NIL


Esto te va a ahorrar el rollete de estar duplicando la condicion la caracter y el bloque y ademas te evita que sea en tiempo de ejecucion cuando te cante que la sintaxis de la condicion (la caracter) esta mal.

Para tu caso asi funcionara, pero el problema que tiene este sistema: no se puede guardar la condicion de filtro para posteriormente restaurarla; quiza en tu ejemplo pasa exactamente lo mismo.

Fuera aparte de tu problema:
En general no me gusta el uso de SET FILTER porque es dificil cambiarlo y restaurarlo. Para ese caso lo que hago es que en el filtro incluyo una variable publica que sera la que encendere o apagare segun necesite apagar o encender el filtro.

Saludos
Posts: 350
Joined: Wed Nov 02, 2005 03:28 PM
Re: Ayuda Dbsetfilter anidado
Posted: Wed Oct 05, 2011 10:57 AM

ok. lo he hecho con dbsetfilter() en lugar de set filter pero funciona de miedo. Gracias.

Saludos,
Regards,

Jose Luis Alepuz
joseluis@mancomputer.com
www.mancomputer.com
Posts: 989
Joined: Thu Nov 24, 2005 03:01 PM
Re: Ayuda Dbsetfilter anidado
Posted: Wed Oct 05, 2011 11:47 AM
Soluci贸n alternativa, para no usar evals:

Code (fw): Select all Collapse
static function filtrararticulo(aVars)
聽 聽 LOCAL cFiltro, aFiltros, i
聽 聽 if Var(1) <= 1 .and. Var(2) <= 1 .and. Var(3) <= 1 .and.;
聽 聽 聽 聽Var(4) <= 1 .and. Var(5) <= 1 .and. Var(5) <= 1
聽 聽 聽 聽msgalert("Debe seleccionar al menos una caracteristica del Articulo.")
聽 聽 聽 聽return ""
聽 聽 endif
聽 聽 (carticulo) ->( dbClearFilter(NIL) )
聽 聽 cfiltro:=""
聽 聽 aFiltros:= {}
聽 聽 IF Var(1) > 1
聽 聽 聽 aAdd( aFiltros, cArticulo+'->ancho=='+Ltrim(Str(tancho[Var(1)]))
聽 聽 ENDIF
聽 聽 IF Var(2) > 1
聽 聽 聽 aAdd( aFiltros, cArticulo+'->densidad=='+Ltrim(Str(tdensidad[Var(2)]))
聽 聽 ENDIF
聽 聽 // .... completar los 5 ifs
聽 聽 cFiltro:= aFiltros[1]
聽 聽 FOR i:= 2 TO Len(aFiltros)
聽 聽 聽 聽 cFiltro+= '.AND.'+aFiltros[i]
聽 聽 NEXT

聽 聽 (carticulo)->(DbSetFilter( &('{||'+cfiltro+'}'), cfiltro ) )
聽 聽 (carticulo)->(dbgotop())

return nil


con esto lo unico que no es constante en el filtro son los propios campos, ni hay evals ni macros salvo al construir el codeblock. Y el filtro se puede salvar y restaurar ya que no depende de variables.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
鈥淚f you think education is expensive, try ignorance"
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Ayuda Dbsetfilter anidado
Posted: Wed Oct 05, 2011 12:26 PM
Estimado Carlos,

Es cierto que el Eval() para filtrar tiene un coste... pero da unas posibilidades que la creacion de la condicion literal no da: se pueden hacer complicadisimas condiciones sin tener que estar construyendo la condicion literal: imaginate si en la condicion tienes que incluir que un campo este contenido en un array 驴 qu茅 hacer ? 驴declarar el array como Private ?; ademas que en la construccion literal el compilador no va a detectar un error de sintaxis hasta el momento en que la condicion es macroevaluada &("{||"+ cFiltro+ "}" ), pero ojo TODA la condicion porque al ser una condicion "condicionada" no esta completa.

Me explico: tu pondrias:
Code (fw): Select all Collapse
Local cVar1:= "algo pasa con mary",;
         dVar2:= Date()
         nVar3:= 12345

aFiltro:= {}
IF lCon1
    Aadd(aFiltro, "CamCar == "+ "'"+ cVar1+ "'")
ENDIF
IF lCon2
    Aadd(aFiltro, "CamFec == CToD("+ DToC(dVar2)+ ")")
ENDIF
IF lCon3
    Aadd(aFiltro, "CamNum == "+ Str(nVar3, 14, ????????))
ENDIF
cFiltro:= aFiltro[1]
FOR nI:= 2 TO Len(aFiltro)
   cFiltro+= ".OR."+ aFiltro[nI]
NEXT
RETURN &("{||"+ cFiltro+ "}")

Este sistema requiere ir transformando cada variable del filtro al tipo apropiado, de manera que cualquier cambio en las variables puede influir en la condicion... vease el numero de decimales para los numericos.


Code (fw): Select all Collapse
Local cVar1:= "algo pasa con mary",;
         dVar2:= Date()
         nVar3:= 12345
Local bFil1:= bFil2:=  bFil3:= {|| .t. },;
         bFiltro:= {|| Eval(bFil1) .AND. Eval(bFil2) .AND. Eval(bFil3) }

IF lCon1
    bFil1:= {|| CamCar == cVar1}
ENDIF
IF lCon2
    bFil2:= {|| CamFec == dVar2 }
ENDIF
IF lCon3
    bFil3:= {|| CamNum == nVar3 }
ENDIF
RETURN bFiltro


El segundo metodo tiene la ventaja que aunque durante las pruebas que hagamos no se cumpla alguna de las condiciones, si hay una expresion sintacticamente erronea, no habra error de sintaxis en tiempo de ejecucion cuando SI se cumpla aquella condicion, porque el compilador habra "revisado" las condiciones, porque no son literales.


Repito... es cierto que hay un coste en el Eval()

Un afectuoso saludo
Posts: 989
Joined: Thu Nov 24, 2005 03:01 PM
Re: Ayuda Dbsetfilter anidado
Posted: Wed Oct 05, 2011 02:39 PM

No veo necesario declarar el array como private, todo depende de la situaci贸n. En el ejemplo que pone el compa帽ero, me gusta m谩s la soluci贸n de la expresi贸n, porque aunque requiera elaborar la expresi贸n como string, 1)me permitir铆a ponerla y quitarla, 2)es m谩s r谩pida seguro, 3)funcionar铆a con ADS (problema que suelo tener que resolver).
Y el array se puede poner como string, tal vez parezca m谩s complicado, pero las ventajas lo compensan.
Si hay un error al elaborar la expresi贸n que solo se v茅 en runtime, bueno... tu tampoco sabes de antemano si estas comparando los tipos correctos de los campos, cuyo tipo solo se puede saber en ejecuci贸n.
Y si hay un error, tarde o temprano vas a tener que corregirlo :D
Es cuesti贸n de gustos, y de las ganas que uno tenga a la hora de currartelo ;)

Por cierto, de donde eres? No lo pone en tu perfil

Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
鈥淚f you think education is expensive, try ignorance"

Continue the discussion