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()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)}