Suchen / Filter ??

Alle Fragen um die Programmierung, die sich sonst nicht kategorisieren lassen. Von Makro bis Codeblock, von IF bis ENDIF

Moderator: Moderatoren

Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Suchen / Filter ??

Beitrag von Rolf Ramacher »

Hallo zusammen,

bei der Kundensuche können gruppen in ein sle-Feld eingegeben werden mit komma getrennt. danach sollen dann nur die Kunden angezeigt werden,
bei denen die Gruppen oder einige Gruppen eingetragen sind. d.h. es müssen nicht alle Gruppen vorhanden sein. also ein Filter setzen von dem Inhalt des feldes bringt nichts. Hat hier jemand eine Idee ?
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14651
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Jan »

Einen Filter mit "$"? Also (spontan ohne jede Prüfung)

cAlias->(DbSetFilter({|| cSuchbegriff $ feldname}))

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Rolf Ramacher »

Hi Jan,

das funkt. noch nicht ganz richtig. ich habe auch nochmal in der Hilfe nachgeschaut und entsprechend nachgebaut.

Code: Alles auswählen

	TmpAdr->(DbSetFilter( {||  lower(alltrim(grpname)) $ lower(alltrim(cGrp))} , 'lower(alltrim(grpname)) $ lower(alltrim(cGrp))' ))
	TmpAdr->(Dbgotop())
	do while Tmpadr->(!eof())
		nc++
		TmpAdr->(DbSkip(+1))
	Enddo
msgbox(var2lchar(nc))
er zeigt nur 1 Datensatz - er muss aber 2 haben.

dies wird als funktion aufgerufen. die darüber gehörende Function sieht so aus.

Code: Alles auswählen

  oXbp:activate := {|| KDGruppe(cGrp),oAnsbrowse:Refreshall() }
aber nach dem Rücksprung aus KDGruppe() welches das filtern durchführt. fliegt mir oAnsbrowse mit einer Fehlermeldung raus. das das Feld
kdnr nicht exisiert. Irgendwie scheint die Datenbank weg zu sein. Oder liegt es daran, dass beim Start der Funktion oAnsBrowse später definiert wird ?
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Rolf Ramacher »

Hat jemand hierzu eine Lösung / idee ??
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9357
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Tom »

Die Bedingung im DO WHILE ist falsch. Das ! gehört vor den Alias.
Herzlich,
Tom
Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Rolf Ramacher »

Hi tom

habe ich geändert. aber trotzdem nur einer
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14651
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Jan »

Rolf,

wie ist denn der Startwert von nc?

Bist Du mal im Debugger durch die Schleife gegangen? Und hast gesehen, WELCHEN Satz er findet (und damit auch, welchen nicht)?

Hast Du mal versucht, den Filter ganz klassisch über Set Filter To zu setzen? Ich hatte schon mal Probleme mit DbSetFilter(). Dann mußt Du aber natürlich vorher die TmpAdr selecten.

Ist sicher, das auf dem aktiven Index von TmpAdr kein Scope liegt, der eventuell den fehlenden Satz ausfiltert?

Noch ein Vorschlag: Du hast eine extrem zeitraubende Filterbedingung eingebaut. Wenn sichergestellt ist, das der Inhalt von TmpAdr->grpname immer klein ist, dann kannst Du Dir das Lower() sparen. Das AllTrim() kannst Du Dir aber auf jeden Fall sparen. Außerdem solltest Du cGrp schon vorher auf Lower setzen. Jede Funktion, die in der Filterbedingung steht, muß für jeden Satz ausgeführt werden. Was auf Dauer extrem performancestörend ist.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Armin
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 393
Registriert: Mo, 26. Sep 2005 12:09
Wohnort: 75331 Engelsbrand
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Armin »

Hallo Rolf,

sieht eigentlich ok aus.
Wenn ich so etwas auf den Grund gehen will, dann baue ich zumindest für den Test eine Benutzerfunktion, die z.B. das Filtern übernimmt. So kann ich debuggen:

Code: Alles auswählen

TmpAdr->(DbSetFilter( {||  testFiltern(lower(alltrim(cGrp)))} , 'lower(alltrim(grpname)) $ lower(alltrim(cGrp))' ))

function testFiltern(cGrp)
local ok:=.f.
local test := lower(alltrim(grpname))
if  test $ cGrp
   ok := .t.
endif
return ok
Gruß, Armin
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von brandelh »

Wie JAN schon geschrieben hat, muss man in der Bedingung unnötige Berechnungen vermeiden, das mach sehr viel aus !
Wenn der kürzere String links steht und einmalig umgesetzt wurde, braucht man in der Schleife nur noch das Feld mit lower() umsetzen, $ findet instring !

Code: Alles auswählen

cSuche := lower(alltrim(cSuche))
do while ! eof()
   if cSuche $ lower(field->Feldx)
      ... nur die mit dem Inhalt aus cSuche
   endif
   skip
endif   
Falls man einen Index setzen kann, zuerst dbSeek() auf den ersten Satz setzen und eine mögliche Endebedingung prüfen.
dblocate() / continue() ist meist schneller als die normale do while skip enddo Konstrukte.
Gruß
Hubert
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9357
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Tom »

Code: Alles auswählen

if cSuche $ lower(field->Feldx)
Verkehrtherum! Wenn "cSuche" einen konkatinierten String enthält ('gute Kunden','mäßig gute Kunden', 'schlechte Kunden'), und das Feld eine Ausprägung davon, muss es so lauten:

Code: Alles auswählen

if lower(field->Feldx) $ cSuche
Herzlich,
Tom
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von brandelh »

Hallo TOM,

in meinem Beispiel enthält cSuche NATÜRLICH den Suchbegriff (z.B. "hans") der im Feld gesucht wird !)
Sollte das oben anders gemeint gewesen sein, nochmals zur Verdeutlichung:

Bei $ muss links immer der kurze Suchstring stehen und rechts der zu durchsuchende String !
Gruß
Hubert
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9357
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Tom »

Und bei der umgekehrten Suche muss NATÜRLICH ein Trim() auf den Feldinhalt erfolgen, da er sonst "trailing blanks" enthält und nicht gefunden wird:

Code: Alles auswählen

IF Trim(Lower(field->Feldx)) $ cSuche
:wink:
Herzlich,
Tom
UliTs
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2828
Registriert: Fr, 10. Feb 2006 9:51
Wohnort: Aachen
Hat sich bedankt: 259 Mal
Danksagung erhalten: 12 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von UliTs »

Das ist ja richtig toll 8) .

Uli
-------
Mitglied XuG Cologne
Mitglied XuG Osnabrück
Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Rolf Ramacher »

leider bin ich hier noch nicht weitergekommen.

Code: Alles auswählen

	sortiere(18)
	TmpAdr->(Dbgotop())
	TmpAdr->(DbSetFilter( {||  lower(alltrim(grpname)) $ lower(alltrim(cGrp))} , 'lower(alltrim(grpname)) $ lower(alltrim(cGrp))' ))
	TmpAdr->(Dbgotop())
	do while !Tmpadr->(eof())
		nc++
		TmpAdr->(DbSkip(+1))
	Enddo
	TmpAdr->(Dbgotop())
msgbox(var2lchar(nc))
	oAnsbrowse:Refreshall()
die einzelnen Werte stehen mit komma getrennt. aber mit oder ohne Komma er findet nichts. und der RefreshAll() bringt eine Fehlermeldung das die Datenbank nicht existiert.
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9357
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Tom »

Nimm mal den Alias in die Filterbedingung:

Code: Alles auswählen

TmpAdr->(DbSetFilter( {||  lower(alltrim(TmpAdr->grpname)) $ lower(alltrim(cGrp))} , 'lower(alltrim(TmpAdr->grpname)) $ lower(alltrim(cGrp))' ))
Dass Dein Browse beim RefreshAll() anschließend meint, die Tabelle nicht zu finden, liegt wahrscheinlich entweder daran, dass Du sie versehentlich zumachst - oder dass sie nicht selektiert ist, aber im Browse ohne Alias referenziert wird.
Herzlich,
Tom
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9357
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Tom »

Anmerkung: Die Wiederholung des Filter-Codeblocks als Zeichenkettenausdruck ist im Normalfall überflüssig. Das benötigt man nur, wenn man z.B. über DbFilter() abfragen möchte, ob ein und, wenn ja, welcher Filterausdruck für eine Workarea aktiv ist. Das hier reicht also:

Code: Alles auswählen

TmpAdr->(DbSetFilter( {||  lower(alltrim(TmpAdr->grpname)) $ lower(alltrim(cGrp))} ))
Herzlich,
Tom
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14651
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Jan »

... und das unnötige Lower() ist auch immer noch drin.

Außerdem ist das DbGoTop() vor dem Filter setzen überflüssig.

Hast Du mal gecheckt, was ich oben geschrieben habe? Was der Startwert von nc ist? Wenn der mit einem negative Wert rein geht dann wird der Wert der Variablen hinterher immer zu klein sein.

Du solltest vielleicht mal nicht einfach hochzählen sondern die RecNo()s in ein Array schreiben. Dann siehst Du auch, welchen Satz der Filter (angeblich) verschluckt.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9357
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Tom »

Jan, ich bin sicher, dass das Problem am fehlenden Alias im Filterausdruck liegt. Vermutlich ist eine andere Tabelle selektiert, die ebenfalls ein Feld "grpname" enthält, so dass der Filter zwar keinen Fehler erzeugt, aber auch wirkungslos ist, da er überhaupt nicht die Inhalte der zu filternden Tabelle prüft. Und, ja, das DbGoTop() vor dem Setzen des Filters ist überflüssig. Man darf es nur danach nicht vergessen. :wink:
Herzlich,
Tom
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14651
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Jan »

Hallo Tom,

*grins* Ja, das DbGoTop() nach einem DbSetFilter() nicht einzubauen kann seeehhhhr ärgerliche und nicht nachvollziehbare Ergebnisse fabrizieren.

Wegen des fehlenden Alias: Ich stimme Dir zu daß der Browse-Fehler daher kommen kann. Aber nicht beim Filter-Ergenis. In der Filterbedingung selber braucht der Alias nicht verwendet zu werden, da hier automatisch der genommen wird, der vor dem DbFilter() steht. Das geht soweit das ich schon Probleme hatte, WEIL ich den Alias in der Filterbedingung drin stehen hatte. Kaum hatte ich den wieder entfernt, lief alles reibungslos. Davor sollte (bzw. muß bei anderer aktiven dbf) der aber stehen. Ich habe mir angewöhnt, grundsätzlich und überall den Alias davor zu setzen, wo das möglich ist. Seitdem passieren wesentlich weniger Fehler während der Laufzeit (egal ob falsche Berechnungen oder Laufzeitfehler). Und das Coden ist dadurch letztendlich wesentlich einfacher und übersichtlicher geworden.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von brandelh »

Tom hat geschrieben:Jan, ich bin sicher, dass das Problem am fehlenden Alias im Filterausdruck liegt.
und ich bin sicher, dass es daran nicht liegt :!: ;-)

Wenn man den Alias auf eine Funktion anwendet, wird in dieser immer der vorher angegebene Selectbereich bearbeitet. Hier also: 'TmpAdr->'[/b]

In dem Code Schnipsel fehlt sowohl die Browser Definition als auch die Startwerte und Grundeinstellungen der Zählvariablen.
Wenn der Filter nur dazu dient die Anzahl von Sätzen zu ermitteln und nicht für die Anzeige selbst benötigt wird, würde ich es so machen:

Code: Alles auswählen

nc := 0
cForVar := "{|| lower(alltrim(field->grpname)) $ ["+lower(alltrim(cGrp))+"] }" // cGrp=" Abc " => [abc] entspricht 'abc', aber [] kann man hier besser unterscheiden.
bForVar := &(cForVar)
TmpAdr->(DbEval( {||  nc++ } , bForVar ))
das ist wesentlich schneller als ein Filter mit do while ! eof()

PS: JAN war schneller ;-)
Gruß
Hubert
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9357
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Tom »

und ich bin sicher, dass es daran nicht liegt
Schauen wir mal. Ich traue Rolf zu, dass er auch noch eine Memvar hat, die wie das Feld heißt. Schaden kann der Alias im Filter jedenfalls nicht. :wink:
Herzlich,
Tom
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von brandelh »

Tom hat geschrieben: Schaden kann der Alias im Filter jedenfalls nicht. :wink:
solange man den richtigen angibt ... ;-)
Gruß
Hubert
Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Rolf Ramacher »

Hallo zusammen,

so hier ist die komplette Function

Code: Alles auswählen

Function KdGruppe(cGrp)
	Local cGrpSuch:=alltrim(lower(cGrp)), aSatz:={}

	If empty(cGrp)
		TmpAdr->(DbClearFilter()) 
		Return Nil
	Endif
msgbox(cgrpsuch)
	sortiere(18)
	TmpAdr->(DbSetFilter( {||  alltrim(lower(TmpAdr->grpname)) $ cGrpSuch}  ))
	TmpAdr->(Dbgotop())
	do while !Tmpadr->(eof())
		AAdd(aSatz,Tmp->(Recno()) )
		TmpAdr->(DbSkip(+1))
	Enddo
	TmpAdr->(Dbgotop())
msgbox(var2lchar(aSatz))
	oAnsbrowse:Refreshall()
Return Nil
in cGrpSuch steht der richtige Wert , aSatz ist leer
@tom memvar nutze ich überhaupt nicht und zu diesem Zeitpunkt ist nur diese Dbf geöffnet.
Hinweis nochmal cGrsuch ist eine Textzeile die in tmpadr->Grpname vorkommen kann. grpname ist c 3000 - kann es daran liegen ?
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Benutzeravatar
Bertram Hansen
Foren-Moderator
Foren-Moderator
Beiträge: 1015
Registriert: Di, 27. Sep 2005 8:55
Wohnort: 51379 Leverkusen
Hat sich bedankt: 28 Mal
Danksagung erhalten: 20 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Bertram Hansen »

Rolf Ramacher hat geschrieben:Hinweis nochmal cGrsuch ist eine Textzeile die in tmpadr->Grpname vorkommen kann. grpname ist c 3000 - kann es daran liegen ?
Hallo Rolf,

hab ich das richtig verstanden, dass das Feld GRPNAME eine Länge von 3000 hat und vom Typ "C" (Zeichenkette) ist?

Bist du sicher das diese Zeilen hier stimmen:

Code: Alles auswählen

AAdd(aSatz,Tmp->(Recno()) )
Du verwendest sonst den Alias TmpAdr.
:wave:
Gruß Bertram
http://www.tobax.de
Mitglied der XUG Cologne
Mitglied der XUG Osnabrück
Beisitzer des Deutschsprachige Xbase-Entwickler e.V.

Solange Kakaobohnen an Bäumen wachsen ist Schokolade Obst!
Benutzeravatar
Rolf Ramacher
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1930
Registriert: Do, 09. Nov 2006 10:33
Wohnort: Bergheim
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Suchen / Filter ??

Beitrag von Rolf Ramacher »

Hallo Bertram,

ja schreibfehler. tmp- jetzt geändert tmpadr->(recno()) aber trotzdem ist leer
Gruß Rolf

Mitglied der Gruppe XUG-Cologne
www.xug-cologne.de
Antworten