Discussion:
ADOQuery.Locate findet falschen Datensatz!
(zu alt für eine Antwort)
Stefan Koschke
2007-05-02 12:38:19 UTC
Permalink
Hallo zusammen,

ich suche per Locate in einer Datenbank:
adoquery1.locate('Deutsch','login :',[]);

In der Datenbank gibt es einen Eintrag "Login :" und einen "login :" und
oben beschriebener Befehl setzt den Zeiger auf den Eintrag mit großem L !
Ist da was bekannt oder gibt es eine Abhilfe?
Die Option ioCaseInSensitive schaltet doch die Prüfung ab und darf für
meinen Fall nicht verwendet werden?!
Ich habe obigen Befehl auch mit dieser Option getestet und es wird wieder
"Login :" gefunden!

Hat jemand bitte einen Denkanstoß für mich?

Ciao
Stefan
Borsdorf, Thomas
2007-05-02 14:07:24 UTC
Permalink
Post by Stefan Koschke
adoquery1.locate('Deutsch','login :',[]);
Hat jemand bitte einen Denkanstoß für mich?
[loCaseInsensitive]
Post by Stefan Koschke
Ciao
Stefan
MfG Thomas.
Robert Wachtel
2007-05-02 14:28:36 UTC
Permalink
Moin!
Post by Borsdorf, Thomas
Post by Stefan Koschke
adoquery1.locate('Deutsch','login :',[]);
Hat jemand bitte einen Denkanstoß für mich?
[loCaseInsensitive]
Du hast das OP aber gelesen, oder?

Robert
Borsdorf, Thomas
2007-05-03 06:09:20 UTC
Permalink
Post by Robert Wachtel
Du hast das OP aber gelesen, oder?
Hmmm... offenbar nicht! Hast recht!

Ich sollte vielleicht nicht zwischen Tür und Angel noch schnell mal auf
Nachrichten antworten...

Gibt es eigendlich ein EDV-Äquivalent zu "Asche auf mein Haupt"?
Post by Robert Wachtel
Robert
MfG Thomas.
Stefan Koschke
2007-05-03 06:17:04 UTC
Permalink
Hallo Thomas,
Post by Borsdorf, Thomas
Post by Robert Wachtel
Du hast das OP aber gelesen, oder?
Hmmm... offenbar nicht! Hast recht!
Ich sollte vielleicht nicht zwischen Tür und Angel noch schnell mal auf
Nachrichten antworten...
Gibt es eigendlich ein EDV-Äquivalent zu "Asche auf mein Haupt"?
"Spannungsabfälle auf mein Motherboard" ?

Ciao
Stefan
Martin Behrens
2007-05-02 21:35:11 UTC
Permalink
Post by Stefan Koschke
adoquery1.locate('Deutsch','login :',[]);
In der Datenbank gibt es einen Eintrag "Login :" und einen "login :" und
oben beschriebener Befehl setzt den Zeiger auf den Eintrag mit großem L !
Ist da was bekannt oder gibt es eine Abhilfe?
Ja, das ist bekannt. ADO kennt u. a. kein Locate. Es wird über nicht
case-sensitive Filter nachgebaut.
Post by Stefan Koschke
Die Option ioCaseInSensitive schaltet doch die Prüfung ab und darf für
meinen Fall nicht verwendet werden?!
Nein, sie wird ignoriert.
Post by Stefan Koschke
Ich habe obigen Befehl auch mit dieser Option getestet und es wird wieder
"Login :" gefunden!
Hat jemand bitte einen Denkanstoß für mich?
Evtl. ADOBetterDataSet oder eine where Bedingung.


Martin
Stefan Koschke
2007-05-03 06:04:15 UTC
Permalink
Hallo Martin,
Post by Martin Behrens
Post by Stefan Koschke
adoquery1.locate('Deutsch','login :',[]);
In der Datenbank gibt es einen Eintrag "Login :" und einen "login :" und
oben beschriebener Befehl setzt den Zeiger auf den Eintrag mit großem L !
Ist da was bekannt oder gibt es eine Abhilfe?
Ja, das ist bekannt. ADO kennt u. a. kein Locate. Es wird über nicht
case-sensitive Filter nachgebaut.
schöne Sch.... ;-)
Dann frage ich mich warum es dann die Option loCaseInsensitive gibt wenn die
Grundfunktion Locate schon so arbeitet.
Post by Martin Behrens
Post by Stefan Koschke
Die Option ioCaseInSensitive schaltet doch die Prüfung ab und darf für
meinen Fall nicht verwendet werden?!
Nein, sie wird ignoriert.
Post by Stefan Koschke
Ich habe obigen Befehl auch mit dieser Option getestet und es wird wieder
"Login :" gefunden!
Hat jemand bitte einen Denkanstoß für mich?
Evtl. ADOBetterDataSet oder eine where Bedingung.
leider dürfen bei uns keine Fremdkomponenten verwendet werden, ich bin also
auf das angewiesen, was D5 Ent. an Board hat.
Eine SQL-Abfrage mit Where ist zwar möglich, ist aber für meine Zwecke viel
zu langsam.
Hintergrund : es handelt sich um eine Übersetzungsdatenbank, es sollen
innerhalb kurzer Zeit einige 1000 deutsche Passagen gefunden und ihre
fremdsprachigen Übersetzungen ermittelt werden. Und eigentlich kommt jede
deutsche Textpassage eben nur ein einziges Mal in der Datenbank vor.

Ich habe es auch schon mit Filter versucht, aber auch da wird die
Groß/Kleinschreibung ignoriert, ist aber um einiges schneller als einzelne
SQL-Abfragen.
Wenn nicht jemand eine bessere Lösung hat, muß ich in den sauren Apfel
beißen und eine Kombination von Filter und dann das Filter-Ergebnis einzeln
durchsuchen einbauen.

Ciao
Stefan
Hans-Joerg Vasold
2007-05-03 18:06:38 UTC
Permalink
Post by Stefan Koschke
Hallo Martin,
Wenn nicht jemand eine bessere Lösung hat, muß ich in den sauren Apfel
beißen und eine Kombination von Filter und dann das Filter-Ergebnis
einzeln durchsuchen einbauen.
Wenn Du an der Struktur der db spielen darfst (ansonsten gehts meist auch
mit berechneten Feldern) besteht die Möglichkeit die betreffende Spalte ein
zweites mal (doppelt so gross wie zuvor) anzulegen und Dich um die Kodierung
selbst zu kümmern.

Natürlich musst Du Einfüge und Änderungsoperationen Rechnung tragen (am
besten Trigger)

Nehmen wir mal an das Alphabet aus dem Deine Suchwörter gebildet werden
besteht aus insgesamt 49 verschiedenen Zeichen, die könntest Du mit 0-49
nummerieren

a = "01", b = "02", c = "03", [..] l="12",m="13",n="14",o="15"

und das ganze nochmal für die GROSSEN ab Zeichen 50

A = "51", B = "52", C="53" , [..] L="62", M="63",N="64",O="65"

Wichtig ist das das oben _keine_ Integerwerte sind, sondern das jedes ASCII
Zeichen des Ursprungsstrings, im neuen zu bildenden String durch zwei andere
ASCII Zeichen ersetzt wird.

Bei Deinem Problem "Login :" und "login :" ergeben sich

"Login :" = "6215060814"
"login :" = "1215060814"

also zwei unterschiedliche Suchmuster.

Natürlich musst Du Dein Suchwort auch vor einer Suche "transformieren", das
heißt das die Funktion zur Transformation der Eingabe in der Datenbank und
die Funktion zum Transformieren Deines Suchwortes das gleiche Ergebnis
liefern.

hth Ha-Jö
Stefan Koschke
2007-05-04 06:39:24 UTC
Permalink
Hallo Ha-Jö,
Post by Hans-Joerg Vasold
Post by Stefan Koschke
Hallo Martin,
Wenn nicht jemand eine bessere Lösung hat, muß ich in den sauren Apfel
beißen und eine Kombination von Filter und dann das Filter-Ergebnis
einzeln durchsuchen einbauen.
Wenn Du an der Struktur der db spielen darfst (ansonsten gehts meist auch
mit berechneten Feldern) besteht die Möglichkeit die betreffende Spalte
ein zweites mal (doppelt so gross wie zuvor) anzulegen und Dich um die
Kodierung selbst zu kümmern.
Natürlich musst Du Einfüge und Änderungsoperationen Rechnung tragen (am
besten Trigger)
Nehmen wir mal an das Alphabet aus dem Deine Suchwörter gebildet werden
besteht aus insgesamt 49 verschiedenen Zeichen, die könntest Du mit 0-49
nummerieren
a = "01", b = "02", c = "03", [..] l="12",m="13",n="14",o="15"
und das ganze nochmal für die GROSSEN ab Zeichen 50
A = "51", B = "52", C="53" , [..] L="62", M="63",N="64",O="65"
Wichtig ist das das oben _keine_ Integerwerte sind, sondern das jedes
ASCII Zeichen des Ursprungsstrings, im neuen zu bildenden String durch
zwei andere ASCII Zeichen ersetzt wird.
Bei Deinem Problem "Login :" und "login :" ergeben sich
"Login :" = "6215060814"
"login :" = "1215060814"
also zwei unterschiedliche Suchmuster.
Natürlich musst Du Dein Suchwort auch vor einer Suche "transformieren",
das heißt das die Funktion zur Transformation der Eingabe in der Datenbank
und die Funktion zum Transformieren Deines Suchwortes das gleiche Ergebnis
liefern.
interessanter Denk-Ansatz :-)
Zugriff auf die DB-Struktur habe ich, kann da also Änderungen /
Erweiterungen machen.
Was ich nun ausprobieren muß ist die Performance. Da ist mir momentan noch
nicht klar, ob ein locate und nachträgliches direktes Suchen in den
gefundenen Datensätzen oder das umcodieren des Suchstrings schneller wird.
Wie gesagt, ich muß einen Weg finden, mehrere Tausend Einträge innerhalb
kurzer Zeit zu finden.

Ciao
Stefan
Erich Günthner
2007-05-04 06:53:54 UTC
Permalink
Hallo Stefan.
mal ne blöde Frage:
Warum nimmst du nicht ne Query?

Select * From DeineTabelle Where 'Deutsch' like 'login :'

Liefert dir alle Einträge aus deiner Tabelle die du brauchst.

Gruß

Erich
Post by Stefan Koschke
Hallo zusammen,
adoquery1.locate('Deutsch','login :',[]);
In der Datenbank gibt es einen Eintrag "Login :" und einen "login :" und
oben beschriebener Befehl setzt den Zeiger auf den Eintrag mit großem L !
Ist da was bekannt oder gibt es eine Abhilfe?
Die Option ioCaseInSensitive schaltet doch die Prüfung ab und darf für
meinen Fall nicht verwendet werden?!
Ich habe obigen Befehl auch mit dieser Option getestet und es wird wieder
"Login :" gefunden!
Hat jemand bitte einen Denkanstoß für mich?
Ciao
Stefan
Stefan Koschke
2007-05-04 08:04:36 UTC
Permalink
Hallo Erich,
Post by Erich Günthner
Hallo Stefan.
Warum nimmst du nicht ne Query?
Select * From DeineTabelle Where 'Deutsch' like 'login :'
Liefert dir alle Einträge aus deiner Tabelle die du brauchst.
Ich habe eine Access - MDB und greife per ADOConnection / ADOQuery / DBGrid
darauf zu.
Wenn ich die Suche über ADOQuery.sql.text := '....' mache muß vorher immer
ADOQuery.Close und danach ADOQuery.open ausgeführt werden und das braucht
ca. 10 Mal so lange wie ein 'Selext * from Texte' und dem nachfolgenden
Locate innerhalb dieser Daten.
Nur Locate macht eben keinen Unterschied zwischen Groß/Kleinschreibung,
ebensowenig wie das Setzen eines Filters.
Ich denke, daß die Benutzung meiner Datenbank nicht so ganz im Sinne des
gesamten SQL-Systems ist:
Normalerweise hat man eine MDB mit ein paar Tausend Datensätzen, von denen
aber immer nur ein paar 100 zu selektieren sind.
Da wirken sich die Abfragezeiten nicht aus. In meinem Fall aber habe ich ca.
12000 Einträge einer Übersetzungsdatenbank, in der von allen unseren
Projekten die deutschen Textpassagen und die zugehörigen Übersetzungen in 12
Sprachen vorliegen.
Um nun die Projekte mehrsprachig zu machen muß jede deutsche Passage des
Programms in dieser Datenbank einzeln (und mit Berücksichtigung der
Groß/Klienschreibung) gesucht werden und die zugehörigen fremdsprachigen
Einträge werden dann je nach Projekt in eine Ressourcendatei gepackt, als
XML-File erstellt oder direkt in den Programm-Source geparst.

Bis vor einiger Zeit war die Datenbank eine reine Textdatei die mittels
TStringAligngrid gehandelt wurde (3000 Zeilen und 13 Sprachen) , nun aber
sind etliche neue Projekte hinzugekommen und da ging diese Lösung nicht
mehr.

Vielleicht habe ich mich mit der Datenbank ja verrannt und es gibt für
diesen speziellen Zweck einen ganz anderen / besseren Ansatz?

Ciao
Stefan
Günter Kieninger
2007-05-04 12:02:45 UTC
Permalink
Post by Stefan Koschke
Vielleicht habe ich mich mit der Datenbank ja verrannt und es gibt für
diesen speziellen Zweck einen ganz anderen / besseren Ansatz?
Du könntest den INhalt der DB-Tabelle in eine Memorytabelle (zB
kbmmemtable) stecken und dann suchen. Mir scheint die ganze sache ist ja
read-only und ziemlich statisch.

Gruß aus den Bergen
Günter
Stefan Koschke
2007-05-04 13:09:09 UTC
Permalink
Hallo Günther,
Post by Günter Kieninger
Post by Stefan Koschke
Vielleicht habe ich mich mit der Datenbank ja verrannt und es gibt für
diesen speziellen Zweck einen ganz anderen / besseren Ansatz?
Du könntest den INhalt der DB-Tabelle in eine Memorytabelle (zB
kbmmemtable) stecken und dann suchen. Mir scheint die ganze sache ist ja
read-only und ziemlich statisch.
ich verstehe leider nur "Bahnhof" :-(
Was meinst Du mit Memorytabelle (zB kbmmemtable) ?
Da wo es auf Geschwindigkeit ankommt ist es wirklich (fast) readonly außer
der gesuchte deutsche Eintrag ist noch nicht enthalten, dann muß er
natürlich hinzugefüg werden.

Ciao
Stefan
Günter Kieninger
2007-05-04 22:03:05 UTC
Permalink
Post by Stefan Koschke
ich verstehe leider nur "Bahnhof" :-(
Was meinst Du mit Memorytabelle (zB kbmmemtable) ?
Das ist im Prinzip ein TDataSet-Abkömmling, der sämtliche Daten im Speicher
hat was es natürlich sehr schnell macht. Es ist einfach auszutauschen und IMO
das beste Teil ist eben TkbmMemTable
(http://www.components4programmers.com/products/kbmmemtable/university/index.
htm)

mit einem
OrgDataSet.SQL.Text := 'Select * from ...';
OrgDataSet.Active := True;
KbmmemTable.LoadFromDataSet(OrgDataSet);
ist am anfang alles getan.
Post by Stefan Koschke
Da wo es auf Geschwindigkeit ankommt ist es wirklich (fast) readonly außer
der gesuchte deutsche Eintrag ist noch nicht enthalten, dann muß er
natürlich hinzugefüg werden.
Was man mittels dem Tool auch machen könnten, ich würde aber hier ne funktion
machen die beide Quellen (DB und Memory) updated.

Gruß aus den Bergen
Günter
Stefan Koschke
2007-05-07 06:25:13 UTC
Permalink
Hallo Günter,
Post by Günter Kieninger
Post by Stefan Koschke
ich verstehe leider nur "Bahnhof" :-(
Was meinst Du mit Memorytabelle (zB kbmmemtable) ?
Das ist im Prinzip ein TDataSet-Abkömmling, der sämtliche Daten im Speicher
hat was es natürlich sehr schnell macht. Es ist einfach auszutauschen und IMO
das beste Teil ist eben TkbmMemTable
(http://www.components4programmers.com/products/kbmmemtable/university/index.
htm)
wie ich in einem anderen Posting geschrieben habe, sollen keine
Fremdkomponenten zum Einsatz kommen :-(
Ich sehe mir das Teil trotzdem mal an, vielleicht kann man ja was abkupfern
;-)
Ansonsten bringt mich das auf die Idee, mit eigenen Mitteln den gesamten
DB-Inhalt in den Speicher zu legen (es sind ja nur ein paar 10MB).
Vielen Dank

Ciao
Stefan
Heinz Zastrau
2007-05-07 15:34:20 UTC
Permalink
Hallo Stefan,
Post by Stefan Koschke
Post by Günter Kieninger
das beste Teil ist eben TkbmMemTable
wie ich in einem anderen Posting geschrieben habe, sollen keine
Fremdkomponenten zum Einsatz kommen :-(
dann nimm TClientDataset. Damit sollte es ähnlich gehen. Oder probier
doch einmal das OnFilter-Event falls es das bei den ADO-Komponenten gibt
(ich weiß aber nicht ob es damit schneller geht, ist nur eine Alternative).

Ciao Heinz Z.
Stefan Koschke
2007-05-08 06:26:52 UTC
Permalink
Hallo Heinz,
Post by Heinz Zastrau
Hallo Stefan,
Post by Stefan Koschke
Post by Günter Kieninger
das beste Teil ist eben TkbmMemTable
wie ich in einem anderen Posting geschrieben habe, sollen keine
Fremdkomponenten zum Einsatz kommen :-(
dann nimm TClientDataset. Damit sollte es ähnlich gehen. Oder probier doch
einmal das OnFilter-Event falls es das bei den ADO-Komponenten gibt (ich
weiß aber nicht ob es damit schneller geht, ist nur eine Alternative).
auch Filter kann Groß/Kleinschreibung nicht unterscheiden :-(
Und im OnFilter nochmal direkt vergleichen ist langsamer als nur Filter zu
setzen und die paar gefundenen Einträge zu vergleichen.

Ciao
Stefan

Loading...