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
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.
(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
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
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
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