ordkeyno() in einem Scope

Auf dem Weg von Clipper, FoxPro u.ä. nach Xbase++

Moderator: Moderatoren

ordkeyno() in einem Scope

Beitragvon Eckhard Sallermann » Mi, 23. Nov 2011 17:01

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
Benutzeravatar
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
 
Beiträge: 88
Registriert: Fr, 29. Jun 2007 12:32
Wohnort: 33330 Gütersloh

Re: ordkeyno() in einem Scope

Beitragvon Tom » Mi, 23. Nov 2011 17:11

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!
Herzlich,
Tom
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
 
Beiträge: 6678
Registriert: Do, 22. Sep 2005 22:11
Wohnort: Berlin

Re: ordkeyno() in einem Scope

Beitragvon AUGE_OHR » Mi, 23. Nov 2011 18:26

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.
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
 
Beiträge: 10141
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg

Re: ordkeyno() in einem Scope

Beitragvon Eckhard Sallermann » Do, 24. Nov 2011 8:20

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
Zuletzt geändert von Eckhard Sallermann am Do, 24. Nov 2011 8:28, insgesamt 1-mal geändert.
Benutzeravatar
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
 
Beiträge: 88
Registriert: Fr, 29. Jun 2007 12:32
Wohnort: 33330 Gütersloh

Re: ordkeyno() in einem Scope

Beitragvon Eckhard Sallermann » Do, 24. Nov 2011 8:27

Ich halte es für weniger gut, alles erst in ein Array zu packen
Benutzeravatar
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
 
Beiträge: 88
Registriert: Fr, 29. Jun 2007 12:32
Wohnort: 33330 Gütersloh

Re: ordkeyno() in einem Scope

Beitragvon Sören » Do, 24. Nov 2011 9:19

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
Sören
Rekursionen-Architekt
Rekursionen-Architekt
 
Beiträge: 196
Registriert: Mo, 07. Aug 2006 9:18
Wohnort: Leipzig

Re: ordkeyno() in einem Scope

Beitragvon Eckhard Sallermann » Do, 24. Nov 2011 10:17

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
Benutzeravatar
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
 
Beiträge: 88
Registriert: Fr, 29. Jun 2007 12:32
Wohnort: 33330 Gütersloh

Re: ordkeyno() in einem Scope

Beitragvon Tom » Do, 24. Nov 2011 10:29

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.
Herzlich,
Tom
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
 
Beiträge: 6678
Registriert: Do, 22. Sep 2005 22:11
Wohnort: Berlin

Re: ordkeyno() in einem Scope

Beitragvon brandelh » Do, 24. Nov 2011 10:32

Hi,

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

DBSkip(50) ;-)
Gruß
Hubert
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
 
Beiträge: 13264
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim

Re: ordkeyno() in einem Scope

Beitragvon Sören » Do, 24. Nov 2011 10:37

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
Sören
Rekursionen-Architekt
Rekursionen-Architekt
 
Beiträge: 196
Registriert: Mo, 07. Aug 2006 9:18
Wohnort: Leipzig

Re: ordkeyno() in einem Scope

Beitragvon Eckhard Sallermann » Do, 24. Nov 2011 11:06

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
Benutzeravatar
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
 
Beiträge: 88
Registriert: Fr, 29. Jun 2007 12:32
Wohnort: 33330 Gütersloh

Re: ordkeyno() in einem Scope

Beitragvon Markus Walter » Do, 24. Nov 2011 11:11

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...
Gruß
Markus

Mitglied der XUG Saarland-Pfalz
Benutzeravatar
Markus Walter
Programmier-Gott
Programmier-Gott
 
Beiträge: 1018
Registriert: Di, 24. Jan 2006 10:22
Wohnort: Saarland

Re: ordkeyno() in einem Scope

Beitragvon Eckhard Sallermann » Do, 24. Nov 2011 11:35

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...
Benutzeravatar
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
 
Beiträge: 88
Registriert: Fr, 29. Jun 2007 12:32
Wohnort: 33330 Gütersloh

Re: ordkeyno() in einem Scope

Beitragvon AUGE_OHR » Do, 24. Nov 2011 20:39

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)}
gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
 
Beiträge: 10141
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg


Zurück zu Migration

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot] und 1 Gast