ordkeyno() in einem Scope

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

Moderator: Moderatoren

Antworten
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
Beiträge: 88
Registriert: Fr, 29. Jun 2007 13:32
Wohnort: 33330 Gütersloh
Kontaktdaten:

ordkeyno() in einem Scope

Beitrag 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
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9343
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 358 Mal
Kontaktdaten:

Re: ordkeyno() in einem Scope

Beitrag 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!
Herzlich,
Tom
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: ordkeyno() in einem Scope

Beitrag 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.
gruss by OHR
Jimmy
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
Beiträge: 88
Registriert: Fr, 29. Jun 2007 13:32
Wohnort: 33330 Gütersloh
Kontaktdaten:

Re: ordkeyno() in einem Scope

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

Re: ordkeyno() in einem Scope

Beitrag von Eckhard Sallermann »

Ich halte es für weniger gut, alles erst in ein Array zu packen
Sören
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 205
Registriert: Mo, 07. Aug 2006 10:18
Wohnort: Leipzig
Danksagung erhalten: 11 Mal

Re: ordkeyno() in einem Scope

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

Re: ordkeyno() in einem Scope

Beitrag 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
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9343
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 358 Mal
Kontaktdaten:

Re: ordkeyno() in einem Scope

Beitrag 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.
Herzlich,
Tom
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: ordkeyno() in einem Scope

Beitrag von brandelh »

Hi,

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

DBSkip(50) ;-)
Gruß
Hubert
Sören
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 205
Registriert: Mo, 07. Aug 2006 10:18
Wohnort: Leipzig
Danksagung erhalten: 11 Mal

Re: ordkeyno() in einem Scope

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

Re: ordkeyno() in einem Scope

Beitrag 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
Benutzeravatar
Markus Walter
Programmier-Gott
Programmier-Gott
Beiträge: 1018
Registriert: Di, 24. Jan 2006 10:22
Wohnort: Saarland

Re: ordkeyno() in einem Scope

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

Mitglied der XUG Saarland-Pfalz
Eckhard Sallermann
UDF-Programmierer
UDF-Programmierer
Beiträge: 88
Registriert: Fr, 29. Jun 2007 13:32
Wohnort: 33330 Gütersloh
Kontaktdaten:

Re: ordkeyno() in einem Scope

Beitrag 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...
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: ordkeyno() in einem Scope

Beitrag 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)}
gruss by OHR
Jimmy
Antworten