Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi 7 MySQL TEXT fields (https://www.delphipraxis.net/216353-delphi-7-mysql-text-fields.html)

KlausV 15. Dez 2024 16:23

Delphi-Version: 5

Delphi 7 MySQL TEXT fields
 
Hallo Zusammen,
ich müsste mal wissen, wieso der RecordCount bei TEXT Feldtypen nicht funktioniert.
In einer Tabelle gibt es Felder vom Typ TEXT.
Wenn ich so ein Feld in meinem SQL verwende und RecordCount benutze, dann steht in RecordCount -1 drin.

Ich hatte zurvor for x:=1 to qry.RecordCount do stehen, habe es nun durch while not eof geändert und so funktioniert es.

Hier der Quellcode:

Code:
        UniDirectional:=True;
        DatabaseName:= 'dbMain';
        SQL.Text:= Format(SQL_Rech_Pos,[Rech_ID]);
        Open;
        First;
        x := 0;
        while not eof do
//        for x:=1 to qry.RecordCount do
         begin
         x:= x +1;
         ....
Entferne ich das Feld vom Typ TEXT aus dem SQL, dann funktioniert auch der recordCount.
Seltsam ist auch, dass überhaupt keine Fehlermeldung hochkommt.
Mache ich etwas falsch?
Danke.
Klaus

Bernhard Geyer 16. Dez 2024 07:49

AW: Delphi 7 MySQL TEXT fields
 
Ich "rate" mal.

UniDirectional bedeutet das der Ergebnisdatensatz nur von "nach Hinten" durchsucht werden kann.
Ich vermute das hier deine verwendeten Zugriffskomponenten auch nicht den gesamten Ergebnissatz übertragen haben, so das (bei größeren Datenmengen)
der Client gar nicht weiß wie viele Datensätze vorhanden sind.
Ohne ntext-Felder ist die Ergebnismenge vermutlich so klein, das sie komplett übertragen wurde.

Lösung:
- Clientservige Curser verwenden (Achtung! Speicherbedarf)
- Programmlogik umbauen, das sie nicht auf RecordCount angewiesen ist

KlausV 16. Dez 2024 08:40

AW: Delphi 7 MySQL TEXT fields
 
Danke.
Ich nutze ganz normal TQUERY.
Code:
qry:=TQuery.Create(nil);
    x := 0;
    With qry do
    begin
    try
        UniDirectional:=True;
        DatabaseName:= 'dbMain';
        SQL.Text:= Format(SQL_Rech_Pos,[Rech_ID]);
        Open;
        First;
        while not eof do
//        for x:=1 to qry.RecordCount do
habe es durch "while not eof" ersetzt, aktuell funktioniert es.

Kann ich auch durch while not eof Probleme bekommen?

Klaus01 16. Dez 2024 08:45

AW: Delphi 7 MySQL TEXT fields
 
.. sollte die Schleife nicht von x := 0 to qry.RecordCount -1 laufen?

Grüße
Klaus

himitsu 16. Dez 2024 08:54

AW: Delphi 7 MySQL TEXT fields
 
Kommt drauf an, was du mit dem X machen willst.
Die RecNo zählt jedenfalls auch von 1 beginnend. :wink:

PS: Beim DataSnap gibt es mit den Streams das Gleiche.
Wenn die Daten in einem Datenblock (waren 32 oder 64 KB) übertragen werden, dann steht Stream.Size auf der realen Datenmenge,
aber bei mehr steht es ebenfalls auf -1 und man muß mit Read so lange lesen, bis Dieses 0 sagt, also bis nichts mehr kommt ... hier würde es also so lange laufen, bis EOF sagt, dass Schluß ist.

Fazit: Wenn es -1 ist dann so lange lesen, bis es endet
oder wenn das nicht -1 sein soll, dann den Modus wechsel oder schauen, ob es eine Art "FetchAll" Befehl gibt, welcher angibt, dass erstmal alle Daten geholt werden müssen, bevor es weitergeht.

Delphi.Narium 16. Dez 2024 10:44

AW: Delphi 7 MySQL TEXT fields
 
For 1 to RecordCount ist schlicht und einfach eine schlechte Idee, egal welche Datenbankkomponente genutzt wird.

Je nach Datenbank und Komponente werden die Datensätze geliefert, sobald sie zur Verfügung stehen, das heißt aber nicht, dass beim Liefern der ersten Datensätze bereits bekannt ist, wieviele Datensätze überhaupt insgesamt geliefert werden (könnten).

Willst Du vorab die exakte Datensatzzahl wissen, musst Du zuerst ein Query.Last machen. Das kann dann dauern und braucht ggfls. auf Client- und/oder Serverseite viel Speicher.

Je nach Datenbankkomponente und/oder Konfiguration kann über ein Fetchattribut bestimmt werden, wieviele Datensätze "am Stück" geholt werden sollen. Steht das z. B. auf 100, so werden nur die ersten 100 Datensätze geholt und RecordCount steht dann auf 100. Per While not EoF wird beim ersten Next hinter dem 100. Datensatz gemerkt: "Oh, da ist ja noch was!" Dann werden die nächsten 100 Sätze geholt und RecordCount "wächst" auf 200 ...
Erst wenn bei einem Next die Info von der Datenbank kommt: "Mehr hab' ich nicht!" ist EoF erreicht und die While not EoF-Schleife wird beendet. Nur so bekommst Du verlässlich alle Datensätze.

Je nach Datenbank und/oder Clientkonfiguration kann es auch sein, dass für die Übermittlung der Daten eine bestimmte Menge Speicher reserviert wird. Ist der voll, wird die Datenübertragung (vorerst) beendet, bis per Next der erste Datensatz "hinter" der bereits gelieferten Datenmenge angefordert wird. Dann kommt der nächste "Schub" Datensätze und RecordCount "wächst" auf die nun gelieferte Gesamtmenge an Datensätzen.

Wenn Du bisher mit For x := 1 to RecordCount immer alle Datensätze bekommen hast, hast Du eher Glück gehabt. Eine sichere Verarbeitung aller Datensätze hast Du so aber sicherlich nicht programmiert.

Alle Datensätze bekommst Du nur mit While not EoF oder Repeat until EoF.

Das von himitsu genannte FetchAll entspricht sinngemäß einem:
Delphi-Quellcode:
qry.Open;
qry.Last;
qry.First;
Dann hast Du alle Datensätze und RecordCount dürfte damit auf der tatsächlich zu erwartenden Anzahl von Datensätzen stehen.

Und wenn Du in X unbedingt wissen muss, um welchen Datensatz es sich handelt, dann nimm einfach x := qry.RecNo, damit hast Du bereits einen Datensatzzähler und musst ihn nicht extra nochmal per for x := 1 to WasWeißIchWieviel, auf eher unzuverlässige Weise, nachbilden.

himitsu 16. Dez 2024 10:50

AW: Delphi 7 MySQL TEXT fields
 
Wobei ja eigentlich die Datenbank weiß, wieviele Datensätze es gibt .... prinzipiell hätte es also möglich sein sollen, dass RecordCount auch mit Fetchin/Windowing immer den richtigen Wert liefert. :stupid:

Delphi.Narium 16. Dez 2024 11:25

AW: Delphi 7 MySQL TEXT fields
 
Nein, nicht unbedingt. Manche Datenbanken fangen bereits an Daten zu liefern, wenn sie noch nicht wissen, wie groß die Datenmenge insgesamt sein wird, sie nur wissen, dass sich an der Reihenfolge ... der zu liefernden Daten nichts mehr ändert.

Hab' es zumindest früher per Toad gegen Oracle-Datenbanken sehen können, dass Programme bei sehr großen Datenmengen bereits mit der Verarbeitung und Ausgabe der Ergebnisse begonnen hatten, während die Datenbank noch mit der Verarbeitung und Lieferung weiterer Daten beschäftigt war.

Sprich: Man konnte beobachten, dass Datenbank und Programm fast gleichzeitig mit der Verarbeitung fertig wurden. Es waren allerdings Prozesse, bei denen die Verarbeitung schon mal in den Bereich von vielen Stunden bis über einen Tag hinaus reichen konnte.

Und bei 'nem Fetch 100 bekommt die Datenbank ja explizit gesagt: Liefere mir bitte die ersten 100 Sätze. Sie schaut dann erst garnicht, ob es mehr geben könnte. Erst wenn der 101. Satz angefordert wird, schaut sie nach den nächsten 100 und weiß damit erst dann, wenn es weniger als 100 weitere Sätze gibt, dass EoF erreicht ist und welcher Wert für RecordCount definitiv zu vergeben ist. In dieser Konstellation sagt RecordCount immer nur aus, wieviele Sätze bereits geliefert wurden, aber nicht, wieviele Sätze insgesamt geliefert werden könnten.

TigerLilly 16. Dez 2024 11:51

AW: Delphi 7 MySQL TEXT fields
 
RecordCount wird clientseitig ausgewertet, indem tatsächlich alle Datensätze abgerufen und gezählt werden. Abgesehen davon, dass das langsam ist, kann sich im Laufe der Bearbeitung die Anzahl der Datensätze ändern (Mehrbenutzer!). Entweder kapselt man das in Transaktionen (read repeatability) oder man iteriert nur über den Cursor. UniDirectional heißt, dass man nur vorwärts lesen kann, aber nicht zurück + das auch nur, wenn der Cursor am Server ist und die Daten nicht am Client.

Wie auch immer: Der Datentyp eines Feldes beeinflusst RecordCount nicht. Da hat es etwas anderes. Der zitierte Code unterschlägt ein WITH irgendwo + wie das SQL wirklich aussieht wär auch gut zu wissen.

Delphi.Narium 16. Dez 2024 12:16

AW: Delphi 7 MySQL TEXT fields
 
Zitat:

Zitat von TigerLilly (Beitrag 1544293)
RecordCount wird clientseitig ausgewertet, indem tatsächlich alle Datensätze abgerufen und gezählt werden.

Das stimmt leider nicht immer. Wenn ich in Delphi 7 mit den Zeoskomponenten und 'ner FireBird-Datenbank arbeite und dabei Fetch 100 gesetzt habe, so kann ich sehen, dass sich im Laufe der Verarbeitung RecordCount ändert. Bei der Nutzung der ADO-Komponenten scheint aber RecordCount sofort auf der tatsächlichen Anzahl von Datensätzen zu stehen.

Früher, mit BDE und DBase, sorgte ein x := qry.RecordCount dafür, dass alle Datensätze gelesen wurden und damit dann die Anzahl der Datensätze bekannt wurde. Aber die Daten wurden erst beim Lesen von RecordCount "geholt", was an der entstehenden Laufzeit bei der Zuweisung von RecordCount auf x zu bemerken war. Diese Laufzeit trat jedoch nicht "so geballt" auf, wenn man per While not EoF die Daten in 'ner Schleife verarbeitete. Aber man wusste dann erst beim Erreichen von EoF wieviele Datensätze verarbeitet wurden.

Und da hier ja Delphi 7 und TQuery (= BDE) genutzt werden, könnte dieser Effekt (und ähnliche (mySQL-bedingete?) Absonderlichkeiten) noch zum Tragen kommen.

TigerLilly 16. Dez 2024 12:19

AW: Delphi 7 MySQL TEXT fields
 
Da hast du schon recht, aber:

Zitat:

Ich nutze ganz normal TQUERY.

Delphi.Narium 16. Dez 2024 12:32

AW: Delphi 7 MySQL TEXT fields
 
Ja, aber bei TQuery verlasse ich mich nicht auf RecordCount, weil es eben nicht bei allen Datenbanken sofort auf dem tatsächlichen Wert der zu verarbeitenden Datensätze steht.

Bei DBase wurde beim Lesen von RecordCount das Lesen der gesamten Datenmenge veranlasst. Aber dies erfolgte nicht grundsätzlich für alle beliebigen Datenbanken, sondern nur bei DBase reproduzierbar.

Und im aktuellen Fall scheint es ja nicht so zu sein, sonst müsste die For-Schleife ja korrekt funktionieren, weil ja spätestens bei
Delphi-Quellcode:
for x := 1 to qry.RecordCount
das holen aller Datensätze engestoßen werden müsste und damit hier ReordCount nicht mehr 1 sein dürfte.

Interessant wäre zu erfahren, ob ein derartiges Konstrukt zu einem geänderten Verhalten führt:
Delphi-Quellcode:
AlleSaetze := qry.RecordCount;
for x := 1 to AlleSaetze do begin
...
end;
Enthält hier dann AlleSaetze die tatsächliche Anzahl an Datensätzen oder auch nur 1?

Redeemer 16. Dez 2024 12:53

AW: Delphi 7 MySQL TEXT fields
 
Zitat:

Zitat von himitsu (Beitrag 1544286)
Wobei ja eigentlich die Datenbank weiß, wieviele Datensätze es gibt ....

MySQL weiß nicht, wie viele Datensätze es gibt. Das weiß es noch nicht mal bei einer ungefilterten Tabelle.

Delphi.Narium 16. Dez 2024 13:10

AW: Delphi 7 MySQL TEXT fields
 
Heißt das, dass ich bei einem
SQL-Code:
select * from tabelle
per
Delphi-Quellcode:
for x := 1 to qry.RecordCount
niemals die tatsächliche, datenbankseitige, Anzahl von Datensätzen bekomme, sondern immer nur die Anzahl der Sätze, die gerade beim Client angekommen ist und dieser dann lokal auswerten kann?

Das würde doch dann bedeuten, dass das im Eingangspost gezeigte Konstrukt der For-Schleife (gegen eine MySQL-Datenbank) noch nie (bzw. nur zufällig) korrekt gearbeitet haben kann?!?

AuronTLG 16. Dez 2024 13:20

AW: Delphi 7 MySQL TEXT fields
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1544306)
Heißt das, dass ich bei einem
SQL-Code:
select * from tabelle
per
Delphi-Quellcode:
for x := 1 to qry.RecordCount
niemals die tatsächliche, datenbankseitige, Anzahl von Datensätzen bekomme, sondern immer nur die Anzahl der Sätze, die gerade beim Client angekommen ist und dieser dann lokal auswerten kann?

Das würde doch dann bedeuten, dass das im Eingangspost gezeigte Konstrukt der For-Schleife (gegen eine MySQL-Datenbank) noch nie (bzw. nur zufällig) korrekt gearbeitet haben kann?!?

Es kommt letztendlich auf die Query-Komponente bzw deren Einstellungen an.
Ich hatte in einem alten Programm mal das Problem, dass das RecordCount genau so lange wunderbar funktioniert hat, wie die tatsächliche Anzahl der Datensätze kleiner oder gleich 50 war, denn in diesem Fall war 50 meine Page-Größe.
Ob das in deinem Fall auch so war, hängt von den Einstellungen der Query ab, die hier schon ausgiebig diskutiert wurden.

Ich habe aus diesem und anderen Gründen der Verwendung von RecordCount schon vor geraumer Zeit abgeschworen, da man zu viele Dinge beachten muss und es dementsprechend eine riesige Fehlerquelle darstellt.

Delphi.Narium 16. Dez 2024 13:30

AW: Delphi 7 MySQL TEXT fields
 
Zitat:

Zitat von AuronTLG (Beitrag 1544307)
Ich habe aus diesem und anderen Gründen der Verwendung von RecordCount schon vor geraumer Zeit abgeschworen, da man zu viele Dinge beachten muss und es dementsprechend eine riesige Fehlerquelle darstellt.

Deshalb schrieb ich ja weiter oben schon:
Zitat:

For 1 to RecordCount ist schlicht und einfach eine schlechte Idee, egal welche Datenbankkomponente genutzt wird.
;-)

TigerLilly 16. Dez 2024 14:57

AW: Delphi 7 MySQL TEXT fields
 
Wie gesagt: Je nach Implementierung zählt RecordCount einfach. Aber auch wenn nicht bzw wenn man selber per COUNT() die Anzahl ermittelt, heißt das nicht, dass sich die Anzahl in Folge nicht ändern kann. Stichworte: Transaktionen/Isolation Level.

Also: for i:=1 to RecordCount ist jedenfalls nicht gut. Besser Next until EOF.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:10 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz