Set scope

Zugriff, Engines, Konvertierung. Von ADS über DBF bis zu SQL.

Moderator: Moderatoren

Antworten
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Set scope

Beitrag von saul »

Hallo,
ich habe eine Datenbank mit ca. 100000 Datensätzen und muß häufiger Begriffe in einem Feld suchen. Ich habe bisher mit Set Scope (verbleiben ca. bis zu 400 Datensätze) und dann mit set Filter gearbeitet. Das ging im Prinzip, aber bei ca. 2% der Suchevorgänge wurden im Netzwerk bis zu 40 Sekunden (Zeiten bis Daten auf Schirm sichtbar sind) gebraucht. Lange hat es gedauert bis ich dem Problem auf die Spur kam.

Code: Alles auswählen

*  kennzeich C 6 Stellen
*  gr1 C 2 Stellen
*  gr2 C 2 Stellen
*  gr3 C 2 Stellen
*  bezeich C 50 Stellen
  mkennzeich:="D-EIBN"
  use	lfzzeit
  index on kennzeich TAG ("kennzeichen") to lfz_zken
  index on kennzeich+ gr1 + gr2 + bezeich+ gr3 TAG ("lfzliste") to lfz_zlis
  set order to ("lfzliste")                       	//       zusammengesetzt  kennzeichen + gr1 + gr2 + bezeich + gr3
* set order to ("kennzeichen")   	                 // nicht zusammengesetzt   kennzeichen

  SET SCOPE  TO mkennzeich	                        // ist nur das Kennzeichen sichtbar

  set filter to "100"$upper(bezeich)                 // Filterfunktion
* set filter to "FRI"$upper(bezeich)                 // Filterfunktion
  ** FRI dauert wesentlich länger bei zusammengesetztem Index
  go top
  browse()
Das Problem scheint beim Set scope mit dem Index zusammen zu hängen.
Zusammengesetzer Index: Suche ich mit Set filter nach "100" so dauert das im Netzwerk 0,06 Sekunden, bei "FRI" (scheint ein Teil der 2% zu sein) ca. bis zu 20 Sekunden.
Index nur auf kennzeichen: In beiden Fällen nur ca. 0,06 Sekunden.
Der Aufbau vom browse() dauert dabei so lange. Beim Xbasepart xbpbrowse und refresh() das gleiche Problem.
Nun benötige ich aber für die Anzeige den zusammengesetzten Index auf jeden Fall. Aber selbst wenn ich eine Zeile vor dem Browse() auf den zusammengesetzten Index umschalte bleibt die lange Zeit.
Hat eine eine Idee wie ich die beiden Anforderungen unter einen Hut bekomme?

mfg
Wolfgang
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: Set scope

Beitrag von AUGE_OHR »

saul hat geschrieben:Ich habe bisher mit Set Scope und dann mit set Filter gearbeitet.
ich würde zunächst mal

Code: Alles auswählen

SET OPTIMIZE OFF
bei SET FILTER versuchen ...

ein Browse hat ja einen "Skipper" (o:skipBlock) und der Filter wäre eine Bedingung.

Code: Alles auswählen

   oBrowse:skipBlock     := {|x| GoNext(x, {|| A = B .AND. C <> D } ) }

//===========================================================================
/*
 GoNext()
 Skip routine for a filtered browse
 SYNTAX:  GoNext(expN1, expB1)
    <expN1> -  number of records to skip
    <expB1> -  block while condition to test for during skip
 RETURNS: number of records actually skipped
 --------------------------------------------------------------------------*/
STATIC FUNCTION GoNext(nToSkip, bWhileCond )
   LOCAL nSkipped := 0, nDirection
   nDirection := IIF(nToSkip > 0, 1, -1)
   DO WHILE nSkipped != nToSkip .AND. EVAL(bWhileCond) .AND. ;
     !EOF() .AND. !BOF()
      SKIP nDirection
      nSkipped += nDirection
   ENDDO
   IF EOF().or. RECNO()==LASTREC()+1
      SKIP -1
      nSkipped--
   ELSEIF BOF()
      GOTO RECNO()
      nSkipped++
   ELSEIF !EVAL(bWhileCond)
      SKIP -nDirection
      nSkipped += -nDirection
   ENDIF
   RETURN nSkipped
gruss by OHR
Jimmy
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: Set scope

Beitrag von saul »

Hallo,
leider funktioniert das bei mir noch nicht und ich verstehe nicht warum. Darf ich vielleicht nochmal nachfragen.

nToSkip = übergebene 1 oder -1 je nach dem ob Cursor up oder down gedrückt wurde
bWhileCond = übergebene Filterbedingung
nDirection := IIF(nToSkip > 0, 1, -1) = Zähler je nach Richtung
DO WHILE nSkipped != nToSkip .AND. EVAL(bWhileCond) .AND. !EOF() .AND. !BOF()
SKIP nDirection
nSkipped += nDirection
ENDDO
Do while so lange bis ein Datensatz gefunden wird?? Müste es dann nicht !EVAL(bWhileCond) heißen?
Was bedeutet bzw. hat nSkipped != nToSkip für eine Funktion?


mfg
Wolfgang
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9355
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 101 Mal
Danksagung erhalten: 361 Mal
Kontaktdaten:

Re: Set scope

Beitrag von Tom »

Hallo, Wolfgang.

Mach mal den Smartfilter an (SET SMARTFILTER ON). Das bewirkt, dass sich das Workarea-Objekt Datensätze merkt, wenn es zum ersten Mal auf sie tritt und sie der Filterbedingung genügen. Wird dann ein solcher Datensatz beim nächsten Mal angefasst (und das passiert beim Browsen häufig), wird die Filterbedingung nicht mehr geprüft, was dramatisch schneller ist.

Den Smartfilter setzt man mit DbRefresh() auf der jeweiligen Workarea zurück, also wenn Daten aktualisiert werden müssen. Beim Schließen einer Tabelle geht er automatisch verloren.

Ich würde aber davon abraten, das grundsätzlich einzuschalten, sondern nur innerhalb der fraglichen Systematik. Und es funktioniert übrigens auch sehr gut. Im Gegensatz zu SET OPTIMIZE und SET RUSHMORE, jedenfalls in 1.9 SL1.
Herzlich,
Tom
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: Set scope

Beitrag von AUGE_OHR »

saul hat geschrieben:leider funktioniert das bei mir noch nicht und ich verstehe nicht warum. Darf ich vielleicht nochmal nachfragen.
klar !

du hast

Code: Alles auswählen

 oBrowse:skipBlock     := {|x| GoNext(x, {|| <Bedingung> } ) }
in deinen Browse Code eingebunden ? du kannst den Code in GoNext per Debugger verfolgen ?
saul hat geschrieben:nToSkip = übergebene 1 oder -1 je nach dem ob Cursor up oder down gedrückt wurde
nicht nur denn zunächst baut sich ja das Browse ( Tbrowse oder XbpBowse ? ) auf
saul hat geschrieben:bWhileCond = übergebene Filterbedingung
YUP
saul hat geschrieben:nDirection := IIF(nToSkip > 0, 1, -1) = Zähler je nach Richtung
YUP
saul hat geschrieben:DO WHILE nSkipped != nToSkip .AND. EVAL(bWhileCond) .AND. !EOF() .AND. !BOF()
SKIP nDirection
nSkipped += nDirection
ENDDO
Do while so lange bis ein Datensatz gefunden wird?? Müste es dann nicht !EVAL(bWhileCond) heißen?
NEIN, die Bedingung EVAL(bWhileCond) soll ja erfüllt werden.
saul hat geschrieben:Was bedeutet bzw. hat nSkipped != nToSkip für eine Funktion?
du kannst statt != auch <> sagen.
denke daran das es auch eine PgUp und PgDown gibt wo die Anzahl von den angezeigten ROWs abhängig ist.
im Grunde heisst es : mach weiter bis du was findest ... und das für jede ROW die angezeigt wird.

ich vergass zu sagen das man die <Bedingung> auch in oBrowse:goTopBlock() und oBrowse:goBottomBlock() übernehmen muss

Code: Alles auswählen

FUNCTION GoTop( bWhileCond )
   WHILE EVAL( bWhileCond ) .AND. !BOF()
      SKIP - 1
      IF !EVAL( bWhileCond )
         SKIP
         EXIT
      ENDIF
   END
RETURN ( NIL )

FUNCTION GoBottom( bWhileCond )
   WHILE EVAL( bWhileCond ) .AND. !EOF()
      SKIP
   END
   SKIP - 1
RETURN ( NIL )
wie aber auch Tom schon sagte solltest du dir die "Optimierung" von SET FILTER genauer anschauen.
SET OPTIMIZE sollte OFF sein sonst gibt es mit FILTER oder auch $ manchmal komische Ergebnisse. ( siehe dazu auch diverse PDRs )
gruss by OHR
Jimmy
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: Set scope

Beitrag von saul »

Hallo,
laut Beschreibung ist set smartfilter immer on. Ich habe ihn nicht abgechaltet. Ich habe mal mit off und on probiert. Es ist für mich aber kein Unterschied zu erkennen. Aslo scheint smartfilter nichts mit meinem Problem zu tun zu haben oder?

mfg
Wolfgang
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: Set scope

Beitrag von AUGE_OHR »

saul hat geschrieben:Also scheint smartfilter nichts mit meinem Problem zu tun zu haben oder?
was soll es bringen wenn die "Optimierung" vorher falsch läuft ?
du solltest zuerst SET OPTIMIZE OFF ausprobieren ob damit die "Pausen" weg sind bevor du weitere Faktoren mit ins Spiel bringst
gruss by OHR
Jimmy
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: Set scope

Beitrag von saul »

Hallo,
habe ich probiert, macht aber keinen Unterschied. Ich bin jetzt an der Lösung mit dem Filter in skip.

mfg
Wolfgang
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: Set scope

Beitrag von AUGE_OHR »

saul hat geschrieben:habe ich probiert, macht aber keinen Unterschied.
hm ... Index neu aufgebaut ?
sprechen wir von CDX oder NTX ?

hier paar (open) PDR Beispiele wo SET OPTIMIZE OFF hilft
5457
Spontaneous Program Termination (SPT), Strategies

o Use SET OPTIMIZE OFF to avoid any problems with the
Xbase++ expression OPTIMIZEr.
o Compile your source code with /o:nospeed to avoid
any optimization problems. See PDR 4220
5227
CDXDBE fails on SET FILTER TO with $ operator

Using SET FILTER TO with the $ operator returns an empty
result set using the CDXDBE
5133
SET FILTER raises IDSC if alias name is invalid

If the alias name in a filter expression is invalid and
it is used in a function like EMPTY(), an IDSC is raised
instead of an error "unknown/invalid name of alias"
5116
IDSC on Seek using UDF in Filter and Index expression

If a user defined function (UDF) is used in an index expression and the
same UDF is used in a filter expression at the same time, then
an IDSC (internal data structures corrupted) error may occour
5024
PRIVATE vars in optimized filter expression not supported

see 4657
4657
LOCAL vars in optimized filter expression are not supported

Setting a filter condition with embedded LOCAL variables and using the
new optimization technique of Xbase++ version 1.70 may not reflect
the correct record set as in the example below
5023
dbSetFilter()/dbClearFilter() eats up memory
5008
SET FILTER with negated compound expression fails

A compound filter expression that is negated as complete expression
or each expression part itself returns a wrong result set.
5007
SET FILTER with a substr() in the expression ignores .NOT.

SET FILTER where the left side of the expression is a substring of a
field returns a wrong result if the expression is denied. It behaves
the same as if the denial isn't used.
5001
SET FILTER with a substring of the indexed field fails

SET FILTER, where the left side of the filter expression is a
substring of the indexed field fails.
4971
DbSkip(0) might hang the application

DbSkip(0) might hang the application if a filter is set.
This does not mean it hangs the application with every database,
on some databases it works and on some others not. The only precondition
is the database must have deleted record
gruss by OHR
Jimmy
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: Set scope

Beitrag von saul »

Hi,
wir sprechen über ntx.
Index schon mehrfach neu erstellt.


mfg
Wolfgang
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: Set scope

Beitrag von saul »

Hallo,
ich habe jetzt mal mit der Filterbedingung gespielt. Füge ich eine Filterbedingung ein, so funktioniert die Anzeige nicht. Es wird mir immer nur die erste Zeile der Datei gezeigt. Um zu verstehen was da passiert habe ich die Filterbedingung in der Do while erstmal weggelassen und im xbpbrowse ein Fenster mit 6 Zeilen Anzeige geschaffen. Nachstehender Code funktioniert.

Code: Alles auswählen

  	::ABrowse:skipBlock      := {|n| GoNext(n, {|| "100"$upper(bezeich) } ) }

Code: Alles auswählen

FUNCTION GoNext(nToSkip, bWhileCond )	
  LOCAL nSkipped := 0, nDirection
  nDirection := IIF(nToSkip > 0, 1, -1)  // Zähler für die Richtung des Skips wird festgelegt 1 cursor down, -1 up
  DO WHILE nSkipped != nToSkip .AND. !EOF() .AND. !BOF()
     SKIP nDirection
     nSkipped = nSkipped + nDirection	
  enddo
  IF EOF().or. RECNO()==LASTREC()+1  	
     SKIP -1
     nSkipped--        							 	
  ELSEIF BOF()			 									
     GOTO RECNO()
     nSkipped++				 								
  endif
return nskipped
Beim Aufbau der ersten Anzeige von xbpbrowse wird die diese Funktion einige Male aufgerufen. 6 mal mit hat nToSkip den Wert 1, 1 mal mit dem Wert -6, dann mit dem Wert 0. Dabei erscheint auf dem Bildschirm das Browsefenster allerdings ohne Cursor und Farbgebung der Datensätze. Danach wir wieder 6 mal mit dem Wert 1, dann 1 mal mit dem Wert -6. Dann erscheint auch die Farbgebung der Datensätze und der Cursor.
Nun versuche ich ergründen was da abläuft. In der Datei stehe ich auf dem ersten Datensatz der angezeigt werden soll. Nun wird in der Funktion mit dem Skip ein Sprung auf den nächsten Datensatz durchgeführt und die Zahl 1 zurückgegeben und das 6 mal. Was beddeutet das für die Anzeige? Warum dann aber manchmal -6 und 0 und warum der Durchlauf 2 mal? Kann ich diesen Ablauf eventuell irgendwo nachlesen?

mfg
Wolfgang
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: Set scope

Beitrag von UliTs »

Ich bin mir nicht sicher, aber darf man überhaupt Filter in Verbindung mit Set Scope setzen?

Uli
-------
Mitglied XuG Cologne
Mitglied XuG Osnabrück
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: Set scope

Beitrag von saul »

Aus Hilfe zu set scope:
Hinweis

Es gibt keine Beschränkungen im Hinblick auf Filterbedingungen und Scopes. SET SCOPE und SET FILTER können beliebig miteinander kombiniert werden.

Ebenso gibt es keine Beschränkunen mit SET RELATION TO ... SELECT. Filter, Scopes und eingeschränkte Relationen können gleichzeitig verwendet werden.
Dürfte theoretisch kein Problem darstellen.

mfg
Wolfgang
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21186
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: Set scope

Beitrag von Manfred »

UliTs hat geschrieben:Ich bin mir nicht sicher, aber darf man überhaupt Filter in Verbindung mit Set Scope setzen?

Uli
Da liegt ja gerade die Würze drin. Über Scope und Index schnell "vorfiltern" und dann mit set filter den Rest machen. Das ist sehr viel schneller, als direkt mit Set Filter zu arbeiten.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
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: Set scope

Beitrag von brandelh »

zu SET RELATION in Verbindung zu FILTERN gibt es einige offene PDR ...
Gruß
Hubert
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: Set scope

Beitrag von UliTs »

brandelh hat geschrieben:zu SET RELATION in Verbindung zu FILTERN gibt es einige offene PDR ...
Ja, habe ich damit verwechselt.
Uli
-------
Mitglied XuG Cologne
Mitglied XuG Osnabrück
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: Set scope

Beitrag von AUGE_OHR »

saul hat geschrieben:

Code: Alles auswählen

  	::ABrowse:skipBlock      := {|n| GoNext(n, {|| "100"$upper(bezeich) } ) }
füge mal ein ALIAS-> "im" Codeblock ein !
gruss by OHR
Jimmy
saul
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 284
Registriert: So, 26. Mär 2006 12:23

Re: Set scope

Beitrag von saul »

Hallo,
ich habe mir jetzt das Programm geändert, sodass ich eine Datei browsen kann in dem die Filterbedingung in die Skipfunktion eingebaut habe. Das funktioniert komplett.
Nun wollte ich ein Array browsen und habe nur skip, EOF() und BOF() geändert. Leider funktioniert das teilweise nicht. Da sehe ich im Moment den Wald vor lauter Bäumen nicht.

Code: Alles auswählen

// Grafischer Browser für Array
  #include "Appevent.ch"
  #include "Common.ch"
  #pragma Library( "XppUi2.lib" )

  PROCEDURE AppSys
    // Desktop bleibt Anwendungsfenster
  RETURN

  PROCEDURE Main
  privat nEvent:=0, mp1:="", mp2, oXbp, oBrowse, cField, i
  privat filter:=""
  aArray:={}   // Daten aus Masterdatei
  for I = 1 to 24
    aadd(aArray,{ str(i,6,0), "Zeile"+str(i,6,0) } )
  next
  nRecno:= 1
  nLastRec := LEN(aArray)
  
  filter:="3"
  ** damit auf erstem zutreffenden Satz steht
  do while !eval({|| upper(filter)$upper(aArray[nrecno,1])} ) .and. nrecno<>nlastrec
    nrecno ++
  enddo
  // Dialogfenster versteckt erzeugen
  oXbp := GuiStdDialog( "Standard GUI Browser for DBF" )

  // Browser im Fenster erzeugen
  oBrowse := GuiBrowseDb( oXbp:drawingArea )

  // Spalten für alle Felder anfügen
  oBrowse:addColumn( {|| aArray[nRecno,1] }, 6 , "Rec"  )
  oBrowse:addColumn( {|| aArray[nRecno,2] }, 8 , "Zeile"  )

  // Der Browser füllt nach :resize() immer das Fenster aus
  oXbp:drawingArea:resize := {|mp1,mp2,obj| obj:childList()[1]:setSize(mp2) }
  oXbp:show()
  oBrowse:show()

  DO WHILE nEvent <> xbeP_Close
    nEvent := AppEvent( @mp1, @mp2, @oXbp )
    oBrowse:HandleEvent ( nEvent, mp1, mp2 )
  ENDDO
  oBrowse:destroy()
RETURN
   ******************************************************************
   * GUI Browser mit Navigations-Codeblöcken für DBF erzeugen
   ******************************************************************
  FUNCTION GuiBrowseDB( oParent, aPos, aSize )
    LOCAL oBrowse
    oBrowse := XbpBrowse():new( oParent,, aPos, aSize ):create()
    
    oBrowse:SkipBlock     := {|nSkip,oBrowse| Skipfilter(nSkip, {|| upper(filter)$upper(aArray[nrecno,1])} ) }

    oBrowse:GoBottomBlock := {|| nRecno := LEN(aArray) }
    oBrowse:GoTopBlock    := {|| nRecno := 1 }
    oBrowse:PosBlock      := {|| nRecno }
    oBrowse:PhyPosBlock   := {|| nRecno }
    oBrowse:LastPosBlock  := {|| LEN(aArray) }
    oBrowse:FirstPosBlock := {|| 1 }
  RETURN oBrowse

   ******************************************************************
   * Standard Dialogfenster versteckt erzeugen
   ******************************************************************
   FUNCTION GuiStdDialog( cTitle )
      LOCAL oDlg
      DEFAULT cTitle TO "Standard Dialog Window"
      oDlg          := XbpDialog():new( ,,{200,50}, {440,400},, .F. )
      oDlg:icon     := 1
      oDlg:taskList := .T.
      oDlg:title    := cTitle
      oDlg:create()
      oDlg:drawingArea:setFontCompoundName( "16.curier new" )
   RETURN oDlg

FUNCTION skipfilter(wert1, wert2 )
   privat nSkipped:= 0 	 		// nSkipped Anzahl der Zeilen, die im Browse bewegt wird 0= Ende erreicht zeigt an
   privat nDirection		 		// legt Richtung für BrowseZeiger fest
   privat nToskip:=wert1 		// Anzahl der Zeilen, die Browsezeiger springen soll
   privat bWhileCond:=wert2	// Filterbedingung

   nDirection := IIF(nToSkip > 0, 1, -1)		// Richtung für skip wird festgelegt

  IF EVAL(bWhileCond)				// steht auf Satz bei dem Filter zutrifft
    // nRecno + ntoskip > nLastRec = EOF , nRecno +nToSkip < 1 = BOF
    DO WHILE nSkipped != nToSkip .AND. EVAL(bWhileCond) .AND. !(nRecno + ntoskip > nLastRec) .AND. !nRecno +nToSkip < 1	// skipped so lang wie Satz zutrifft
      nRecno += nDirection
      nSkipped += nDirection
      DO WHILE !EVAL(bWhileCond) .AND. !(nRecno + ntoskip > nLastRec) .AND. !nRecno <= 1	// skipped weiter bis wieder auf einem zutreffenden Satz steht
        nRecno += nDirection
      ENDDO
    ENDDO
  ELSE                      // Filter trifft nicht zu
    DO WHILE !EVAL(bWhileCond) .AND. !(nRecno + ntoskip > nLastRec) .AND. !nRecno + nToSkip < 1 // skipped weiter bis wieder auf einem zutreffenden Satz steht
      nRecno += nDirection
    ENDDO
    if !(nRecno >= nLastRec) .AND. !nRecno + nToSkip < 1		// steht auf einen anzuzeigenden Datensatz
      nSkipped += nDirection
     ENDIF
    ENDIF

    IF (nRecno + ntoskip > nLastRec)                                      	// eof() 
      nRecno = nLastRec
      nSkipped--
      DO WHILE !EVAL(bWhileCond) .AND. !nRecno + ntoskip < 1	// skipped weiter bis wieder auf einem zutreffenden Satz steht
        nRecno -= 1
      ENDDO
    ELSEIF nRecno + nToSkip < 1				// BOF
      nRecno = 1
      DO WHILE !EVAL(bWhileCond) .AND. !(nRecno + ntoskip > nLastRec) // skipped weiter bis wieder auf einem zutreffenden Satz steht
        nRecno += 1
      ENDDO
      nSkipped++
    ENDIF
RETURN nSkipped
Es macht nochmal einen Unterschied ob die Filterbedingung auf das letzte Arrayelement zutrifft oder nicht. Hat jemeand eine Idee?

mfg
Wolfgang
Antworten