Seite 1 von 1

Problem mit INDEX-Tag bei absteigender Sortierung

Verfasst: Mo, 19. Mär 2007 11:50
von Lewi
Hallo miteinander!

Folgendes Problem: Ich möchte die Datensätze sortiert nach IDNR (Datentyp: „C“ und Preis (Datentyp „N“ , wobei ich eine absteigende Sortierung haben möchte. (xBase 1.82)

Für eine aufsteigende Sortierung nutze ich einen Index mit folgendem Tag-Aufbau:

Code: Alles auswählen

FIELD->IDNR + Transform( FIELD->PREIS, '@L0 999,999.99')
Die Reihenfolge ist wie gewünscht:
  • 4,000.00
    4,500.00
    5,000.00
    5,500.00
    7,800.00
    7,900.00
    7,950.00
Wenn ich nun den kontrollierenden Index für ein absteigende Sortierung wie folgt aufbaue:

Code: Alles auswählen

FIELD->IDNR + DESCEND( Transform( FIELD->PREIS, '@L0 999,999.99') )
erhalte ich eine Reihenfolge, die nicht streng absteigend ist:
  • 7,800.00
    7,950.00
    7,900.00
    5,500.00
    5,000.00
    4,500.00
    4,000.00
Mal abgesehen davon, dass mich die Reichenfolge „verblüfft“, wo liegt mein „Denkfehler“ beim Aufbau des TAGS?

Ach ja, weder ein REORG noch eine Abänderung des Wertes „7,800.00“ auf z.B. „7,820.00“ ändert etwas an der Reichenfolge.

Gruß, Olaf

Verfasst: Mo, 19. Mär 2007 12:01
von Martin Altmann
Hallo Olaf,
DESCEND hat so seine Probleme (derzeit)!
Bau Dir Dein eigenes DESCEND:

Code: Alles auswählen

FIELD->IDNR + Transform( 999999.99 - FIELD->PREIS, '@L0 999,999.99') )
Viele Grüße,
Martin

Verfasst: Mo, 19. Mär 2007 12:10
von brandelh
Hi,

eventuell stören die eingefügten Tausendertrennzeichen.
Versuche mal ob str(descend(nWert),x,y) besser funktioniert.

Verfasst: Mo, 19. Mär 2007 15:04
von Lewi
Bei der Funktion DESCEND() scheint es tatsächlich wohl unter xBase 1.82 einen Bug zu geben.

Wenn ich eine Testdatei wie folgt indiziere:

Code: Alles auswählen

ordCondSet( ,  ,, , ,  , RECNO(), , , , .F. )   // DESCENDIG Methode
ordCreate("TEST.CDX", "1", , {|| FIELD->IDNR + Transform( 999999.99 - FIELD->PREIS,"@L0 999999.99")}, , .F. )
dann erfolgt zwar eine korrekte absteigende Reihenfolge, allerdings wird über Seek( DESCEND( “1”) [1=steht für eine IDNR, alphanumerisch] kein Datensatz gefunden. Die wäre aber wiederum erforderlich um die gewünschte Listenausgabe zu erhalten.


Wenn ich einen INDEX Tag mittels Descend() eine absteigende Sortierung über

Code: Alles auswählen

ordCreate("TEST.CDX", "1", , {|| DESCEND(FIELD->IDNR + Transform( 999999.99 - FIELD->PREIS,"@L0 999999.99"))}, , .F. )
erreichen möchte, dann führt dies zu einer fehlerhaften Reihenfolge.


Mein turn arround basiert auf Martins Lösungsansatz:

Code: Alles auswählen

ordCreate("TEST.CDX", "5", , {|| FIELD->IDNR + Transform( 999999.99 - FIELD->PREIS,"@L0 999999.99")}, , .F. )

Hubert, Dein Lösungsvorschlag

Code: Alles auswählen

str(descend(nWert),x,y
greift nicht, da der Ausdruck „Str(Descend(FIELD->PREIS),8,2)“ zu einer negativen Zahl (ohne Str() ) führt und die Sortierung demnach aufsteigend wäre (z.B. -4000 < -2000 )


Gruß, Olaf

Verfasst: Mo, 19. Mär 2007 15:14
von Tom
Hallo, Olaf.

Code: Alles auswählen

Index on (99999999999 - db->wert) to index.ntx
(ggf. noch mit Transform oder Str)

Nicht elegant, funzt dafür immer.

Verfasst: Mo, 19. Mär 2007 15:25
von Lewi
Tom, ich brauche für einige Listen (mit FRAX) einen zusammengesetzten Index aus "IDNR" + "PREIS".
Ob nun der INDEX auf einem Tag oder einer separaten Index-Datei basiert scheint mir im Zusammenhang mit dem DESCEND() Problem weniger "lösungsrelvant" zu sein.

Ist Alaska das Problem mit der Descend() Funktion bekannt???

Gruß, Olaf

Verfasst: Mo, 19. Mär 2007 16:30
von brandelh
Lewi hat geschrieben:Hubert, Dein Lösungsvorschlag

Code: Alles auswählen

str(descend(nWert),x,y
greift nicht, da der Ausdruck „Str(Descend(FIELD->PREIS),8,2)“ zu einer negativen Zahl (ohne Str() ) führt und die Sortierung demnach aufsteigend wäre (z.B. -4000 < -2000 )
Genau das ist gewünscht, und gleichzeitig das Problem.

descend(400) -> -400
descend(500) -> -500

Wird nun der Index nur auf die Descend(nr) gelegt, stimmt die Sortierung, da nummerisch die Reihenfolge so ist:

-500
-400

was wir ja wollten.

Wenn man aber STR() dazu mixt, wird nicht mehr nummerisch sondern linksbündig String verglichen.

A-400 // kleiner bei Textvergleich.
A-500

Ob dies nun ein Fehler bei der Umsetzung von descend() ist lasse ich mal dahingestellt. Zumindest die Dokumentation sollte erklären, dass nummerische Variablen nicht mit Descend und str() verwendet werden dürfen. Descend() setzt einfach das - BIT. Es bleibt also nichts anderes übrig, als TOMs oder Martins Weg einzuschlagen.

Verfasst: Mo, 19. Mär 2007 16:34
von brandelh
Lewi hat geschrieben:Tom, ich brauche für einige Listen (mit FRAX) einen zusammengesetzten Index aus "IDNR" + "PREIS".
Ob nun der INDEX auf einem Tag oder einer separaten Index-Datei basiert scheint mir im Zusammenhang mit dem DESCEND() Problem weniger "lösungsrelvant" zu sein.
Für solche temporären Listen hat Stefen den SORT Befehl vorgeschlagen.
Wenn man mit SetScope die Grenzen eng setzt, dann in SORT mit der FOR Klausel den Rest ausfiltert, nur die Felder nimmt die man wirklich braucht und flexibel sortiert, wäre das sehr schnell. Eine sortierte DBF macht auf jeden Fall bei Fremdprodukten weniger Ärger als ein Index.

Nur so als Idee ...

Verfasst: Mo, 19. Mär 2007 22:09
von Lewi
Logisch

Ich bin dem Problem noch einmal auf dem Grund gegangen und zum Ergebnis gekommen, dass die Funktion DESCEND() in Verbindung mit Index-Ausdrücken zur Erzeugung von absteigenden Indexen im Zusammenhang mit alphanumerischen + numerischem Feld nicht geeignet ist.

Der Grund dafür liegt nicht in einer fehlerhaften Implementierung der DESCEND() Funktion sondern darin, dass für ein Index-Tag bzw. eine Index-Datei bei der Nutzung von einem numerischen Feld in Verbindung mit einem alphanumerischen Feld der Indexausdruck immer ein String zurück geben muss. Somit erfolgt die Reihenfolge über einen String-Vergleich.

Die nachfolgenden Beispiele sollen dies verdeutlichen. Aus Gründen der Übersichtlichkeit verzichte ich auf ein über mehrere Felder zusammengesetzten Indexausdruck, sondern betrachte ich Nachfolgenden ein einfaches PREIS-Feld.
  • FIELD->PREIS
    1
    4000
    7000
    12000
Bei String-Vergleichen gelten folgende Bedingungen:

Aufsteigende Reihenfolge: „ “ < „-„ < „0“ oder chr(32) < chr(45) < chr(48 )
Absteigende Reihenfolge: „0“ > „-„ > „ „ oder chr(48 ) > chr(45) > chr(32)

Ein Index mit Str( FIELD->PREIS,6,0) ergibt über den Stringvergleich folgende Reihenfolge:
  • „_____1“
    „__4000“
    „__7000“
    „_12000“
Ein Index unter Verwendung von Transform( FIELD->PREIS, „@L0 999999“) führt über den String-Vergleich zu folgender Reihenfolge:
  • „000001“
    "004000"
    "007000"
    "012000"
Ein Index unter Verwendung von Str( Descend(xWert), 6,0) führt über den String-Vergleich zu folgende Reihenfolge:
  • „____-1“
    „_-4000“
    „_-7000“
    „-12000“
Ein Index unter Verwendung von Transform( DESCEND(FIELD->PREIS), „@L0 999999“) führt über den String-Vergleich zu folgender Reihenfolge:
  • "-12000"
    „-04000“
    „-07000“
    „-00001“
Somit bleibt festzuhalten, dass Str(Descend( nValue ),x,y) bzw. Transform( Descend(nValue), „@L0 999999.99“) nicht geeignet ist, um eine absteigende Sortierung zu erhalten.

Gruß, Olaf

PS: Bedingt durch die proportionale Schrift habe ich zur besseren Visualisierung Leerzeichen mit einem Unterstrich aufgeführt.

Verfasst: Mo, 19. Mär 2007 22:29
von AUGE_OHR
hi,
Lewi hat geschrieben: Somit bleibt festzuhalten, dass Str(Descend( nValue ),x,y) bzw. Transform( Descend(nValue), „@L0 999999.99“) nicht geeignet ist, um eine absteigende Sortierung zu erhalten.
und was ist mit STRZERO() ?

gruss by OHR
Jimmy

Verfasst: Mo, 19. Mär 2007 22:36
von Lewi
Hi Jimmy,
StrZero( nWert,6,0) ist gleichzusetzen mit Transform( nWert, "@L0 999999" ).
Insofern ist Dein Hinweis bereits berücksichtigt.

Gruß, Olaf

Verfasst: Mo, 19. Mär 2007 23:47
von AUGE_OHR
hi,
Lewi hat geschrieben: Bei der Funktion DESCEND() scheint es tatsächlich wohl unter xBase 1.82 einen Bug zu geben.
das selbe passiert auch mit der v1.9x wenn man über einen String geht.

Entgegen den Tip von Tom und Martin würde ich aber nicht "9999999 -"
nehmen sondern das ganze, per "OffSet", ins "positive" bringen also
1.000.000 (bei "N",6 ) und das ganze per #define

Code: Alles auswählen

#define DesOffSet 1000000

FUNCTION MAIN
LOCAL i

   SET COLLATION TO GERMAN

   IF .NOT. FILE("DESDBF.DBF")
      CRE_SETUP("DESDBF.DBF")
   ENDIF

   USE DESDBF EXCLUSIV
   ZAP

   FOR i:= -100 TO 100
      APPEND BLANK
      REPLACE IDNR  WITH "AAAAAA"
      REPLACE PREIS WITH i
   NEXT
   INDEX ON DESDBF->IDNR+STRZERO( (DESDBF->PREIS+DesOffSet),7 ) TO DESNTX

   SEEK( "AAAAAA"+STRZERO(0+DesOffSet,7) )
   BROWSE()

RETURN NIL

FUNCTION CRE_SETUP(datei)
LOCAL field_list:={}
    aadd(field_list,{"IDNR"    ,"C",6,0})
    aadd(field_list,{"PREIS"   ,"N",6,0})

    dbcreate(datei,field_list)
RETURN NIL
gruss by OHR
Jimmy

Verfasst: Di, 20. Mär 2007 5:52
von Martin Altmann
Hallo Jimmy,
AUGE_OHR hat geschrieben:Entgegen den Tip von Tom und Martin würde ich aber nicht "9999999 -" nehmen sondern das ganze, per "OffSet", ins "positive" bringen also 1.000.000 (bei "N",6 ) und das ganze per #define
nur dass es damit latürnich nicht absteigend, sondern nach wie vor aufsteigend sortiert ist :wink:

Viele Grüße,
Martin

Verfasst: Di, 20. Mär 2007 7:05
von AUGE_OHR
moin,
Martin Altmann hat geschrieben: nur dass es damit latürnich nicht absteigend, sondern nach wie vor aufsteigend sortiert ist :wink:
uuups ... da hab ich es genau "anderrum" gemacht, aber kein Problem :

Code: Alles auswählen

   INDEX ON DESDBF->IDNR+DESCEND(STRZERO( (DESDBF->PREIS+DesOffSet),7 )) TO DESNTX

   SEEK( "AAAAAA"+DESCEND(STRZERO(16+DesOffSet,7)) )
so nun ist das DESCEND() drin und funktioniert wohl wie gewünscht, oder ?

gruss by OHR
Jimmy