derzeit versuche ich, einen bestimmten Zeileneintrag in einer 1-spaltigen DB-Grid Tabelle möglichst schnell und „effektiv“ zu suchen und mit dem Cursor zu markieren.
Die einfachste, aber wahrscheinlich die am wenigsten elegante Methode ist das schlichte Prüfen eines jeden Datensatzes der Reihe nach von Anfang an. Bei kurzen Datensätzen kein Problem, die Suchdauer wird aber linear zum Anwachsen der Datei immer länger.
Deshalb habe ich mir die unten stehende Routine ausgedacht: Man geht zum mittleren Datensatz, prüft ob dies ein Treffer ist, oder der gesuchte DS kleiner oder größer ist; dann wieder die Hälfte usw. (sh Code-Beispiel unten). Am Ende möchte ich dann noch, dass der Cursor einigermaßen in der Mitte des Feldes „stehen bleibt“. Geht super schnell, da mit jedem Schritt bereits eine Hälfte der Möglichkeiten "verworfen" wird.
Dieser Code funktioniert sehr gut und sehr schnell, einige Fragen habe ich aber noch:
1. Kann man es vermeiden, dass der Cursor während des Suchvorganges in der Datenbank „so wild“ umherspringt; der Cursor also erst nach Beenden des Suchvorganges in der Datenbank an die richtige Stelle des DBGrids springt?
2. Kann man es möglich machen, dass sich der Cursor nach Finden des Datensatzes „in die Mitte“ der Tabelle setzt? („Mein“ Code funktioniert zwar prächtig, elegant ist er aber sicherlich nicht – ich nehme in Kauf, dass die „Profis“ unter Euch schmunzeln werden).
3. Gibt's „bessere“ und vielleicht auch „fertige“ Suchroutinen? (Sorry: "Bessere" ganz sicher!)
4. Und jetzt mein Hauptproblem: Eine Ewigkeit suchte ich nach dem Grund, warum „meine“ Routine manche Datensätze einfach nicht gefunden hat. Natürlich denkt man zunächst an Fehler im eigenen Algorithmus. Es lag aber an einer ganz verrückten Sache: die Sortierreihenfolge von SQL (SQLite/Zeos) und von Lazarus [ v := AnsiCompareText ( x); ] wird bezüglich des Bindestrichs „ - „ anders" behandelt und anders sortiert, was dazu führt, dass „mein“ Algorithmus den richtigen Datensatz in seltenen Fällen nicht findet. Betroffen sind also nur Wörter, die „in der Nähe“ ein anderes(!) Wort als das Gesuchte mit einem „ - „ [Bindestrich] im Text haben. Die Fehlersuche war deshalb so schwierig, weil ja nicht mal das gesuchte Wort selber diesen Bindestrich enthalten muss, sondern auch ein beliebiges anderes Wort, das eben zufällig in der „Mittensuche“ meines Codes angesprungen wird und dann die Info „weitergibt“, das gesuchte Wort sei „größer als“ anstatt „kleiner als“. In einer lange Reihe von Dateieinträgen war bei mir nur ein Wort „betroffen“, nur weil ein Wort mit einem Bindestrich „ in der Nähe“ war. [Die Fehlersuche war "grausam"]
Danke!
A. Geigenberger
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Code: Alles auswählen
Procedure TForm2.Trimm (Var WString : string); // evtl. Leerstellen abschneiden
begin
Wstring := Trimleft(Wstring);
Wstring := Trimright(Wstring);
end;
procedure TForm2.ZuZeileTextspringen ;
var
i_a, i_e, i_m, v, i : integer;
String_2 : string;
LABEL Sprungpunkt, Sprungpunkt2;
begin
Form2.Trimm(Hilfsstring); // Hilfsstring: glob. Variable = zu suchender Eintrag
i_a := 1;
i_e := Form1.QText.RecordCount;
Sprungpunkt:
i_m := ( i_a + ((i_e - i_a) div 2 ) ); // zu "Mitte" springen
Form1.QText.RecNo:=(i_m );
String_2 := Form1.DBEditTitel.Text; Form2.Trimm(String_2);
v := AnsiCompareText ( Hilfsstring , String_2 );
if ( i_e - i_a ) < 2 then // vorerst also nichts gefunden
begin
Form1.QText.RecNo:=( 1 ); // Anfang und Ende noch Checken
String_2 := Form1.DBEditTitel.Text; Form2.Trimm(String_2);
if Hilfsstring = string_2 then exit;
Form1.QText.RecNo:=( Form1.QText.RecordCount ); // Anfang und Ende noch Checken
String_2 := Form1.DBEditTitel.Text; Form2.Trimm(String_2);
if Hilfsstring = string_2 then exit;
// Showmessage( 'Nix gefunden');
Form1.QText.RecNo:=(1); // nix gefunden -> an den Anfang!
exit;
end;
if v = 0 then // gefunden!
begin // Cursor besser "in die Mitte" bringen
v := (Form1.QText.RecNo - 1);
if v > 7 then v := 7;
For i := 1 to v do form1.QText.Prior;
Form1.QText.MoveBy( v );
v := (Form1.QText.RecordCount - Form1.QText.RecNo);
if v > 7 then v := 7;
For i := 1 to v do form1.QText.Next;
Form1.QText.MoveBy( - v );
exit;
end;
if v = -1 then i_e := i_m else i_a := i_m; // vorher: -1 nachher: 1
goto Sprungpunkt;
end;