Seite 1 von 1

ordkeyno() in einem Scope

Verfasst: Mi, 23. Nov 2011 17:01
von Eckhard Sallermann
Tach auch,

in Clipper ( zumindest mit dem Comix RDD ) hat cmxkeyno() immer die Satznummer im Index in Abhängigkeit vom Scope angezeigt

also wenn ich 10.000 Datensätze habe, setzte einen Scope auf z.B. eine Kundennummer, in diesem Scope befinden sich dann z.B. nur 100 Datensätze.
In Clipper gibt mir dann cmxkeyno() für den ersten Satz im Scope 1 zurück und für den letzten eben 100

Scheinbar kann man das so in XBASE nicht machen, zumindest wird immer die Nummer bezogen auf den gesamten Index zurück gegeben. :(

Habe ich etwas übersehen, oder gibt es da Möglichkeiten ?


Gruß Ecki

Re: ordkeyno() in einem Scope

Verfasst: Mi, 23. Nov 2011 17:11
von Tom
Hallo, Ecki.

Ja, OrdKeyNo() ist lediglich eine Alternative zu RecNo(), mit dem Unterschied, dass ersteres die Position basierend auf dem Index zurückgibt, wobei Scopes, Relationen usw. keine Rolle spielen. Du müsstest Dir also einen Workaround bauen, der beispielsweise nach dem Setzen des Scopes alle Datensatznummern der gescopten Sätze in ein Array packt. Wenn dieses Array dann beispielsweise 100 Einträge hätte, enthielte a[50] die Datensatznummer des fünfzigsten Datensatzes innerhalb des Scopes. Diese Vorgehensweise würde die Anzeige der Datensätze vermutlich etwas verringern, aber das hat die von Dir genannte Hilfsfunktion vermutlich auch getan.

Code: Alles auswählen

aScopeArray := MySetScope(...)

FUNCTION MySetScope(..)
LOCAL aScopeArray := {}
DbSetScope(..)
DbGoTop() // eigentlich nicht erforderlich
DO WHILE !Eof()
  aAdd(aScopeArray,RecNo())
  DbSkip(1)
ENDDO
DbGoTop() // hier IST es erforderlich
RETURN aScopeArray
Ergänzung: Nach dem Löschen/Hinzufügen/Editieren von Datensätzen müsste "aScopeArray" jeweils neu erzeugt werden!

Re: ordkeyno() in einem Scope

Verfasst: Mi, 23. Nov 2011 18:26
von AUGE_OHR
Eckhard Sallermann hat geschrieben:in Clipper ( zumindest mit dem Comix RDD ) hat cmxkeyno() immer die Satznummer im Index in Abhängigkeit vom Scope angezeigt
Xbase++ ist Cl*pper v5.2 kompatible, die "abgespeckte" COMIX Version gab es IMHO erst für v5.3x
ORDKEYNO()
Get the logical record number of the current record

ORDKEYGOTO()
Move to a record specified by its logical record number in the controlling

ORDKEYCOUNT()
Return the number of keys in an order
diese schönen Functionen gibt es unter Xbase++ nicht.
Eckhard Sallermann hat geschrieben:also wenn ich 10.000 Datensätze habe, setzte einen Scope auf z.B. eine Kundennummer, in diesem Scope befinden sich dann z.B. nur 100 Datensätze.
In Clipper gibt mir dann cmxkeyno() für den ersten Satz im Scope 1 zurück und für den letzten eben 100
wenn es 1 - 100 ist stimmt das 1:1 mit DbPosition() überein was nun der Scrollbar nutzt.
wenn du aber 200 Records hast , was du erst mal "feststellen" musst, wären das immer noch 100%
nur die Schrittweite bei 1 Record wäre 0.5% ...
Eckhard Sallermann hat geschrieben:Scheinbar kann man das so in XBASE nicht machen, zumindest wird immer die Nummer bezogen auf den gesamten Index zurück gegeben. :(

Habe ich etwas übersehen, oder gibt es da Möglichkeiten ?
ja GUI ;)
nein im Ernst wenn du es nicht, so wie Tom vorgeschlagen hat, machen willst bleibt dir nur der Scrollbar.

Code: Alles auswählen

   oBrowse:posBlock      := {| | DbPosition()}
   oBrowse:goPosBlock    := {| n | DbGoPosition(n)}
das sind die beiden Codeblöcke dafür.

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 8:20
von Eckhard Sallermann
Na ja, wenn es die Funktion DbPosition() gibt, dann sollte es doch für die Entwickler eigentlich kein Problem sein, so etwas
wie cmxkeyno() zu integrieren, müsste doch machbar sein ?

p.s. ORDKEYCOUNT() lässt sich ja leicht nachbilden

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 8:27
von Eckhard Sallermann
Ich halte es für weniger gut, alles erst in ein Array zu packen

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 9:19
von Sören
Hallo Ecki,

wie Jimmy schrieb, gibt es die Funktionen ORDKEYGOTO() und ORDKEYCOUNT() in Xbase++ nicht.

Die Funktion ORDKEYNO() existiert jedoch. Und die tut ja genau das, was Du suchst: die logische
Datensatz-Nr. einer indizierten DBF-Tabelle zurückgeben (wobei auch Scopes berücksichtigt werden).

Und hier noch eine Funktion die ORDKEYCOUNT() nachbildet:

Code: Alles auswählen

FUNCTION OrdRecCount( ncIndex )

  LOCAL cCurrentTagName
  LOCAL nRec := RecNo()  // aktuellen DS retten
  LOCAL nRecCount := 0, nFirstRec, nLastRec

  // Index-Pos. o. TagName angegeben --> diesen als kontrollierend setzen u. gleichzeitig den
  // alten Index retten, um ihn spaeter wieder herzustellen
  if ! Empty( ncIndex )
    cCurrentTagName := OrdSetFocus( ncIndex )
  endif

  dbGoTop()  // auf ersten (logischen) DS gehen

  if !Eof()

    nFirstRec := OrdKeyNo()  // relative DS-Nr. des 1. DS der indizierten DB feststellen

    dbGoBottom()  // auf letzten (logischen) DS gehen

    nLastRec := OrdKeyNo()  // relative DS-Nr. des letzten DS der indizierten DB feststellen

    nRecCount := ( nLastRec - nFirstRec + 1 )  // Diffz. zw. 1. und letzten DS bilden

  endif

  // wurde der kontrollierende Index oben verstellt, wird er hier wieder hergestellt
  if cCurrentTagName != NIL
    OrdSetFocus( cCurrentTagName )
  endif

  dbGoTo( nRec )  // aktuellen DS wieder herstellen

RETURN nRecCount
Damit sollte es ein Leichtes sein, bei Bedarf auch die Funktion ORDKEYGOTO() nachzubauen.

Beste Grüße,
Sören

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 10:17
von Eckhard Sallermann
Hi Sören,

sorry, ich weiß zwar nicht, wie du das machst, bei mir funktioniert das leider nicht
ORDKEYNO() gibt natürlich einen Wert zurück, dieser bezieht sich aber nicht auf den
Scope, sondern auf die gesamte Datei.

p.s. dann wäre es natürlich ein leichtes Orderkeycount() nachzubilden

Sören hat geschrieben:Hallo Ecki,

wie Jimmy schrieb, gibt es die Funktionen ORDKEYGOTO() und ORDKEYCOUNT() in Xbase++ nicht.

Die Funktion ORDKEYNO() existiert jedoch. Und die tut ja genau das, was Du suchst: die logische
Datensatz-Nr. einer indizierten DBF-Tabelle zurückgeben (wobei auch Scopes berücksichtigt werden).

Und hier noch eine Funktion die ORDKEYCOUNT() nachbildet:

Code: Alles auswählen

FUNCTION OrdRecCount( ncIndex )

  LOCAL cCurrentTagName
  LOCAL nRec := RecNo()  // aktuellen DS retten
  LOCAL nRecCount := 0, nFirstRec, nLastRec

  // Index-Pos. o. TagName angegeben --> diesen als kontrollierend setzen u. gleichzeitig den
  // alten Index retten, um ihn spaeter wieder herzustellen
  if ! Empty( ncIndex )
    cCurrentTagName := OrdSetFocus( ncIndex )
  endif

  dbGoTop()  // auf ersten (logischen) DS gehen

  if !Eof()

    nFirstRec := OrdKeyNo()  // relative DS-Nr. des 1. DS der indizierten DB feststellen

    dbGoBottom()  // auf letzten (logischen) DS gehen

    nLastRec := OrdKeyNo()  // relative DS-Nr. des letzten DS der indizierten DB feststellen

    nRecCount := ( nLastRec - nFirstRec + 1 )  // Diffz. zw. 1. und letzten DS bilden

  endif

  // wurde der kontrollierende Index oben verstellt, wird er hier wieder hergestellt
  if cCurrentTagName != NIL
    OrdSetFocus( cCurrentTagName )
  endif

  dbGoTo( nRec )  // aktuellen DS wieder herstellen

RETURN nRecCount
Damit sollte es ein Leichtes sein, bei Bedarf auch die Funktion ORDKEYGOTO() nachzubauen.

Beste Grüße,
Sören

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 10:29
von Tom
Diese von Sören skizzierte Funktion ermittelt nur die Anzahl der Datensätze im Scope. Das hilft wenig, wenn man zum - relativ - fünfzigsten Datensatz springen will. Und auch DbPosition hilft hier nicht, weil das zwar eine relative Position zurückreicht, aber keine Handhabe für die Navigation.

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 10:32
von brandelh
Hi,

der relativ 50. Datensatz, mit oder ohne Scope, Filter oder ähnliches ?

DBSkip(50) ;-)

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 10:37
von Sören
Hallo Ecki,

das ist merkwürdig, denn es funktioniert bei mir.

Ich verwende allerdings die DBFNTX-DBE und ausschließlich DbSetScope( SCOPE_BOTH, ... ).
Vielleicht hat es ja damit zu tun.
Tom hat geschrieben:Diese von Sören skizzierte Funktion ermittelt nur die Anzahl der Datensätze im Scope. Das hilft wenig, wenn man zum - relativ - fünfzigsten Datensatz springen will.
Hubert hat geschrieben:DBSkip(50)
Genau!

Beste Grüße,
Sören

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 11:06
von Eckhard Sallermann
Sören, ich habe SCOPE_TOP und auch SCOPE_BOTH probiert, kein Erfolg.

Natürlich kann ich auch folgendermaßen vorgehen:

Scope saetzen, dann

dbgobottom()
nLastRec := ordkeyno()
dbgotop()
nFirstRec := ordkeyno()

somit habe ich die Nummer des Ersten und die des Letzten

in meiner Routine kann ich dann wie folgt die aktuelle KeyNO ermitteln

nKeyno := ordkeyno() - nFirstRec + 1


Prinzipiell nicht schlecht, allerdings braucht XBASE bei großen Dateien sehr lange, um jede einzelne ORDKEYNO() zu ermitteln,
also ist das eher eine schlechtere Lösung.



Sören hat geschrieben:Hallo Ecki,

das ist merkwürdig, denn es funktioniert bei mir.

Ich verwende allerdings die DBFNTX-DBE und ausschließlich DbSetScope( SCOPE_BOTH, ... ).
Vielleicht hat es ja damit zu tun.
Tom hat geschrieben:Diese von Sören skizzierte Funktion ermittelt nur die Anzahl der Datensätze im Scope. Das hilft wenig, wenn man zum - relativ - fünfzigsten Datensatz springen will.
Hubert hat geschrieben:DBSkip(50)
Genau!

Beste Grüße,
Sören

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 11:11
von Markus Walter
Hi,

auch hier nochmal der Hinweis, dass lt. Aussage von Alaska die Funktion ORDKEYNO() bei CDX nicht verlässlich sei (Heuristik). Sie stimmt zwar meist, aber ich hatte in der Tat mal Datenkonstellationen, wo diese Funktion völlig falsche Werte lieferte...

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 11:35
von Eckhard Sallermann
Alles schitte :(

Markus Walter hat geschrieben:Hi,

auch hier nochmal der Hinweis, dass lt. Aussage von Alaska die Funktion ORDKEYNO() bei CDX nicht verlässlich sei (Heuristik). Sie stimmt zwar meist, aber ich hatte in der Tat mal Datenkonstellationen, wo diese Funktion völlig falsche Werte lieferte...

Re: ordkeyno() in einem Scope

Verfasst: Do, 24. Nov 2011 20:39
von AUGE_OHR
hi,

ok scheinbar ist mein Hinweis nicht angekommen, also versuche ich es "anders".

Code: Alles auswählen

   oBrowse:posBlock      := {| | DbPosition()}
   oBrowse:goPosBlock    := {| n | DbGoPosition(n)}
das wäre in einem Browse "normal" und wäre 100%

Code: Alles auswählen

   oBrowse:posBlock      := {| | DbPosition()*10    }
   oBrowse:goPosBlock    := {|n| DbGoPosition(n/10) }
   oBrowse:lastPosBlock  := {| | 1000               }
   oBrowse:firstPosBlock := {| | 0                  }
damit hätte ich eine "feiner" Auflösung von 1 : 1000

nun habe ich aber in einem Scope meistens "weniger"

Code: Alles auswählen

   oXbp:phyPosBlock   := {| | Recno()      }
   oXbp:posBlock      := {| | OrdKeyNo()   }
   oXbp:lastPosBlock  := {| | LastRec()    }
   oXbp:firstPosBlock := {| | 1            }
und damit komme ich zu Sören´s Lösung für OrdKeyCount()

Code: Alles auswählen

RETURN nRecCount
das Ergebnis setzt sich ja aus "Bottom" - "Top" zusammen.

Du brauchst also im Prinzip deine eigene Browse Class wo du "Top" und "Bottom" selbst verwaltest

Code: Alles auswählen

   ::XbpBrowse:phyPosBlock   := {|    | ::recNo}
   ::XbpBrowse:firstPosBlock := {|    | ::TopOrdKey + ::PosMyTop}
   ::XbpBrowse:lastPosBlock  := {|    | (::BottomOrdKey - ::PosMyBottom - ::TopOrdKey) +1}
   ::XbpBrowse:posBlock      := {| o  | (::OrdKeyNo  - (::TopOrdKey + ::PosMyTop)) +1}
   ::XbpBrowse:goPosBlock    := {|n, o| ::MyGoPosBlock(n)}