Discussion:
Sortieren im DBGrid bei Datumswerten?
(zu alt für eine Antwort)
Heiko Baumann
2011-06-12 20:35:31 UTC
Permalink
Hallo zusammen,

eine Frage: ich hab in einem DBGrid (genauer: JvDBUltimGrid aus der Jedi
JVCL) Datumswerte (tt.mm.jjjj) angezeigt. Das Grid bringt das Sortieren
durch Mausklick auf den Spaltenkopf von Haus aus mit, das funktioniert
auch soweit, aber bei Datumsangaben stimmts leider nicht ganz, da
offenbar nur die Stringwerte verglichen werden und somit in der
Reihenfolge '01.06.2011' vor '13.05.2011' vor '23.04.2011' kommt, was
eigentlich ja genau anders rum sein müsste.

Gibts da nen Trick wie man das richtig sortieren lassen kann, ohne dass
es von der DB neu erledigt wird? Die Daten sind ja schon alle im Client,
da müsste man ja nicht unbedingt eine neue Abfrage starten.. oder?

Danke!
LG Heiko
Nicole Wagner
2011-06-16 12:12:06 UTC
Permalink
Post by Heiko Baumann
Hallo zusammen,
eine Frage: ich hab in einem DBGrid (genauer: JvDBUltimGrid aus der
Jedi JVCL) Datumswerte (tt.mm.jjjj) angezeigt. Das Grid bringt das
Sortieren durch Mausklick auf den Spaltenkopf von Haus aus mit, das
funktioniert auch soweit, aber bei Datumsangaben stimmts leider nicht
ganz, da offenbar nur die Stringwerte verglichen werden und somit in
der Reihenfolge '01.06.2011' vor '13.05.2011' vor '23.04.2011' kommt,
was eigentlich ja genau anders rum sein müsste.
Gibts da nen Trick wie man das richtig sortieren lassen kann, ohne
dass es von der DB neu erledigt wird? Die Daten sind ja schon alle im
Client, da müsste man ja nicht unbedingt eine neue Abfrage starten..
oder?
Danke!
LG Heiko
Das wuerde ich so nicht machen.

Schreibe eher ein "sort by date" in Deine SQL Abfrage und lasse die
Query auf Klick akutualisieren.

Oder sind die Daten nicht aus der DB?

Nicole
Heiko Baumann
2011-06-16 18:39:11 UTC
Permalink
Post by Nicole Wagner
Post by Heiko Baumann
Hallo zusammen,
eine Frage: ich hab in einem DBGrid (genauer: JvDBUltimGrid aus der
Jedi JVCL) Datumswerte (tt.mm.jjjj) angezeigt. Das Grid bringt das
Sortieren durch Mausklick auf den Spaltenkopf von Haus aus mit, das
funktioniert auch soweit, aber bei Datumsangaben stimmts leider nicht
ganz, da offenbar nur die Stringwerte verglichen werden und somit in
der Reihenfolge '01.06.2011' vor '13.05.2011' vor '23.04.2011' kommt,
was eigentlich ja genau anders rum sein müsste.
Gibts da nen Trick wie man das richtig sortieren lassen kann, ohne
dass es von der DB neu erledigt wird? Die Daten sind ja schon alle im
Client, da müsste man ja nicht unbedingt eine neue Abfrage starten..
oder?
Danke!
LG Heiko
Das wuerde ich so nicht machen.
Schreibe eher ein "sort by date" in Deine SQL Abfrage und lasse die
Query auf Klick akutualisieren.
Oder sind die Daten nicht aus der DB?
Doch doch, das würde sicherlich gehen, allerdings wäre eine erneute
Anfrage an die DB performancetechnisch ungünstig und sogar überflüssig,
da die Daten ja alle bereits beim Client liegen und nur umsortiert
werden müssen.

Hab die Ursache inzwischen gefunden: ich mache dummerweise per SQL über
DATE_FORMAT aus dem Datumsfeld einen String, und dann ist es nicht
verwunderlich, dass das DBGrid falsch sortiert. Wenn das Feld ein echtes
TDate oder TDAtetime ist, klappts mit der nativen Sortierung des Grids
problemlos.

Danke fürs Mitdenken!

LG Heiko
Post by Nicole Wagner
Nicole
Nicole Wagner
2011-06-17 09:08:58 UTC
Permalink
Post by Heiko Baumann
Doch doch, das würde sicherlich gehen, allerdings wäre eine erneute
Anfrage an die DB performancetechnisch ungünstig und sogar
überflüssig, da die Daten ja alle bereits beim Client liegen und nur
umsortiert werden müssen.
Hab die Ursache inzwischen gefunden: ich mache dummerweise per SQL
über DATE_FORMAT aus dem Datumsfeld einen String, und dann ist es
nicht verwunderlich, dass das DBGrid falsch sortiert. Wenn das Feld
ein echtes TDate oder TDAtetime ist, klappts mit der nativen
Sortierung des Grids problemlos.
Danke fürs Mitdenken!
Danke fuer das Posten der Loesung.
Klar, wenn die Abfrage "dauert", ist es guenstiger, keine neu zu
stellen.

Deine Kompomente kenne ich nicht.
Ist sie gut? Kostenlos? Hast Du ein Link?

Warum ich es anders machen wuerde, hat diesen Grund:
Grundsaetzlich ist ein DBGrid nur eine Darstellung. Es "hat" keine
Daten wie ein TStringGrid, sondern zeigt sie nur so an, wie sie in der
DB sind. D.h. wenn Du die Anzeige aendern willst "musst" Du (auch da
gibt es natuerlich Wege, es anders zu machen), die Query zur DB aendern.

Das ist mal die Grundregel, gegen die man was tun kann.
Meiner Erfahrung nach ist es im Zweifel aber effizienter, gegen
Grundregeln NICHTS zu tun. Wenn der Delphi IDE Programmierer und viele,
mit denen Du sprichtst, von der Grundregel ausgehen, dann ist es
leichter fuer Dich und mich, es auch zu tun. Denn im Zweifel schwimme
man mit dem Strom.

Ob ich mit meinen DBGrids nur die DB darstelle? - Leider nein.
Es war ein dorniger Weg, bis es tat, was ich wollte.

Darum habe ich auch gefragt, ob Dein Datum aus der DB kommt.


Nicole
Heiko Baumann
2011-06-18 20:43:53 UTC
Permalink
Post by Nicole Wagner
Deine Kompomente kenne ich nicht.
Ist sie gut? Kostenlos? Hast Du ein Link?
Die Jedi VCL ist doch recht weit verteitet - eine Sammlung aus vielen
vielen Erweiterungen. Manches (meiner Meinung nach) unnütz, manches aber
doch sehr nett.
http://jvcl.delphi-jedi.org/
Post by Nicole Wagner
Grundsaetzlich ist ein DBGrid nur eine Darstellung. Es "hat" keine
Daten wie ein TStringGrid, sondern zeigt sie nur so an, wie sie in der
DB sind. D.h. wenn Du die Anzeige aendern willst "musst" Du (auch da
gibt es natuerlich Wege, es anders zu machen), die Query zur DB aendern.
Das ist völlig klar. Ich will ja nichts ändern, sondern dem Benutzer
einfach die Möglichkeit der Sortierung der Daten zu geben.
Post by Nicole Wagner
Das ist mal die Grundregel, gegen die man was tun kann.
? Das klingt etwas abenteuerlich...
Post by Nicole Wagner
Meiner Erfahrung nach ist es im Zweifel aber effizienter, gegen
Grundregeln NICHTS zu tun. Wenn der Delphi IDE Programmierer und viele,
mit denen Du sprichtst, von der Grundregel ausgehen, dann ist es
leichter fuer Dich und mich, es auch zu tun. Denn im Zweifel schwimme
man mit dem Strom.
Ist mir zu philosophisch. Die Daten liegen in der DB, die Query holt sie
und packt sie in eine bestimmte View, das Grid oder sonstwas zeigt genau
diese Daten an, fertig. Ist doch schön dass es eine so klare logische
Struktur gibt, wozu sollte ich diese "Grundregel" brechen?
Post by Nicole Wagner
Ob ich mit meinen DBGrids nur die DB darstelle? - Leider nein.
Es war ein dorniger Weg, bis es tat, was ich wollte.
Hm. Was kommt denn dann noch rein? Berechnete oder lookup-Felder? Das
zählt doch als DB-Feld. Oder was meinst du?

Na dann, trotzdem Danke und frohes Schaffen..
LG Heiko
Perlsau
2011-06-19 10:35:37 UTC
Permalink
Post by Heiko Baumann
Gibts da nen Trick wie man das richtig sortieren lassen kann, ohne dass
es von der DB neu erledigt wird? Die Daten sind ja schon alle im Client,
da müsste man ja nicht unbedingt eine neue Abfrage starten.. oder?
Sortierungen finden nicht in der Datenbank statt, sondern werden von der
Anwendung, die auf die DB zugreift, erledigt. Ich verwende z.B. die
FibPlus-Komponenten, um auf eine Firebird-Datenbank (2.5) zuzugreifen.
Eine Sortierung mit FibPlus gestaltet sich denkbar einfach:

CASE Spalte OF
0 : FibSet_Titel.DoSort(['INDEX'], [SortOrder]);
1 : FibSet_Titel.DoSort(['TITEL'], [SortOrder]);}
...
END;

Spalte ist hier eine globale Variable, die mit der jeweiligen Spalte im
DBGrid korrespondiert. FibSet_... sind Datasets, SortOrder ist Boolean,
gibt die Sortierrichtung an. Klicke ich auf den Titel einer Spalte
(OnTitleClick) im DBGrid, wird zuerst geprüft, ob der Column-Index mit
Spalte identisch ist. Wenn ja, löst das ein SortOrder := Not Sortorder
aus: Die Sortierrichtung wird umgekehrt. Wenn nein, geschieht ein
SortOrder := TRUE und die globale Variable Spalte wird auf den Wert der
neu zu sortierenden Spalte im DBGrid gesetzt.

Steht dir kein DoSort zur Verfügung, verwendest du zum Sortieren SQL:

PROCEDURE Sort_Titel(Spalte : INTEGER);
VAR
Merk : INTEGER;
SQL : STRING;

BEGIN
Merk := DatMod.FibSet_Titel.FieldByName('INDEX').AsInteger;
CASE Spalte OF
0 : BEGIN
DatMod.FibSet_Titel.Close;
SQL := 'SELECT * FROM TITEL ORDER BY INDEX';
IF SortOrder THEN SQL := SQL + 'ASC' ELSE SQL := SQL + 'DESC';
DatMod.FibSet_Titel.SQLs.SelectSQL.Text := SQL;
DatMod.FibSet_Titel.Open;
END;
1 : BEGIN
DatMod.FibSet_Titel.Close;
SQL := 'SELECT * FROM TITEL ORDER BY LOWER(TITEL) ';
IF SortOrder THEN SQL := SQL + 'ASC' ELSE SQL := SQL + 'DESC';
DatMod.FibSet_Titel.SQLs.SelectSQL.Text := SQL;
DatMod.FibSet_Titel.Open;
END;
...
END;

Die Sortierung findet also definitiv nicht in der Datenbank statt,
sondern wird von deinem Dataset oder Query erledigt. Die SQL-Befehle
sorgen dafür, daß die Daten in der gewünschten Reihenfolge aus der DB
gelesen werden. Möchtest du nach Lookup-Feldern sortieren, empfiehlt
sich der Befehl "inner join". Nehmen wir an, ich habe in meiner Tabelle
TITEL ein Feld REGIE, das auf die Tabelle REGIE verweist und in es nur
ein Integer steht, nämlich der Primärschlüssel aus der Tabelle REGIE.
Dann muß der SQL-Befehl so aussehen:

SELECT * FROM REGIE
INNER JOIN TITEL
ON REGIE.INDEX=TITEL.REGIE
ORDER BY REGIE.NAME
Heiko Baumann
2011-06-24 09:52:17 UTC
Permalink
Nach kurzer Auszeit (Gardasee *g*) wieder zurück...
Post by Perlsau
Sortierungen finden nicht in der Datenbank statt, sondern werden von der
Anwendung, die auf die DB zugreift, erledigt. Ich verwende z.B. die
FibPlus-Komponenten, um auf eine Firebird-Datenbank (2.5) zuzugreifen.
CASE Spalte OF
0 : FibSet_Titel.DoSort(['INDEX'], [SortOrder]);
1 : FibSet_Titel.DoSort(['TITEL'], [SortOrder]);}
...
END;
Ja, genau so geht das auch mit den Zeos-Komponenten. Mein Problem war
aber, dass ich bereits in der Query aus dem Datumsfeld einen String
gemacht hab (format_date...) und dadurch die Strings richtigerweise
falsch sortiert wurden (01.05.2011 kommt vor 07.04.2011 kommt vor
21.01.2011).
Post by Perlsau
PROCEDURE Sort_Titel(Spalte : INTEGER);
VAR
Merk : INTEGER;
SQL : STRING;
BEGIN
Merk := DatMod.FibSet_Titel.FieldByName('INDEX').AsInteger;
CASE Spalte OF
0 : BEGIN
DatMod.FibSet_Titel.Close;
SQL := 'SELECT * FROM TITEL ORDER BY INDEX';
IF SortOrder THEN SQL := SQL + 'ASC' ELSE SQL := SQL + 'DESC';
DatMod.FibSet_Titel.SQLs.SelectSQL.Text := SQL;
DatMod.FibSet_Titel.Open;
END;
1 : BEGIN
DatMod.FibSet_Titel.Close;
SQL := 'SELECT * FROM TITEL ORDER BY LOWER(TITEL) ';
IF SortOrder THEN SQL := SQL + 'ASC' ELSE SQL := SQL + 'DESC';
DatMod.FibSet_Titel.SQLs.SelectSQL.Text := SQL;
DatMod.FibSet_Titel.Open;
END;
...
END;
Die Sortierung findet also definitiv nicht in der Datenbank statt,
sondern wird von deinem Dataset oder Query erledigt. Die SQL-Befehle
sorgen dafür, daß die Daten in der gewünschten Reihenfolge aus der DB
gelesen werden.
Na dann geht die Anfrage doch nochmal neu an die DB, genau das wollte
ich ja umgehen. Aber schöner Quelltext - frag mich nur ob du das für
jede Query extra machst oder das irgendwie generalisierst, sonst wäre es
doch ein ziemlicher Aufwand, oder?

Danke für die Antwort!
Perlsau
2011-06-24 12:28:04 UTC
Permalink
Post by Heiko Baumann
Post by Perlsau
CASE Spalte OF
0 : FibSet_Titel.DoSort(['INDEX'], [SortOrder]);
1 : FibSet_Titel.DoSort(['TITEL'], [SortOrder]);}
...
END;
Ja, genau so geht das auch mit den Zeos-Komponenten. Mein Problem war
aber, dass ich bereits in der Query aus dem Datumsfeld einen String
gemacht hab (format_date...) und dadurch die Strings richtigerweise
falsch sortiert wurden (01.05.2011 kommt vor 07.04.2011 kommt vor
21.01.2011).
Solches sollte man tunlichst vermeiden. Ich kann mir keinen Fall
vorstellen, für den man bereits in der Query ein Datums- oder
Integerfeld in ein Stringfeld umwandeln müßte. Datumsformatierungen
lassen sich gewöhnlich ebenfalls in der Query vornehmen, ohne daraus
einen String zu machen.
Post by Heiko Baumann
Post by Perlsau
PROCEDURE Sort_Titel(Spalte : INTEGER);
VAR
Merk : INTEGER;
SQL : STRING;
BEGIN
Merk := DatMod.FibSet_Titel.FieldByName('INDEX').AsInteger;
CASE Spalte OF
0 : BEGIN
DatMod.FibSet_Titel.Close;
SQL := 'SELECT * FROM TITEL ORDER BY INDEX';
IF SortOrder THEN SQL := SQL + 'ASC' ELSE SQL := SQL + 'DESC';
DatMod.FibSet_Titel.SQLs.SelectSQL.Text := SQL;
DatMod.FibSet_Titel.Open;
END;
1 : BEGIN
DatMod.FibSet_Titel.Close;
SQL := 'SELECT * FROM TITEL ORDER BY LOWER(TITEL) ';
IF SortOrder THEN SQL := SQL + 'ASC' ELSE SQL := SQL + 'DESC';
DatMod.FibSet_Titel.SQLs.SelectSQL.Text := SQL;
DatMod.FibSet_Titel.Open;
END;
...
END;
Die Sortierung findet also definitiv nicht in der Datenbank statt,
sondern wird von deinem Dataset oder Query erledigt. Die SQL-Befehle
sorgen dafür, daß die Daten in der gewünschten Reihenfolge aus der DB
gelesen werden.
Na dann geht die Anfrage doch nochmal neu an die DB, genau das wollte
ich ja umgehen.
Wieso? Ich finde es funktioaler, wenn ein DBGrid den Zustand der
korrespondierenden Query exakt darstellt. Sonst hast du u.U. im DBGrid
eine ganz andere Sortierung als z.B. im entsprechenden Formular. Für
mich bleibt der Grundsatz bestehen: Sortierungen und sonstige
Darstellungs-Sachen immer soweit wie möglich in der Query regeln. Im
DB-Grid werden lediglich Farben, Titel- und Record-Schrift usw. eingestellt.
Post by Heiko Baumann
Aber schöner Quelltext - frag mich nur ob du das für
jede Query extra machst oder das irgendwie generalisierst, sonst wäre es
doch ein ziemlicher Aufwand, oder?
Wie sollte ich es denn sonst machen? Jede Tabelle benötigt ihre ganz
eigenen SQL-Befehle. Davon abgesehen "füttern" meine Sortier-Proceduren
meist auch noch die Statuszeile mit entsprechendem Text wie "sortiert
nach Titel aufwärts" etc. Davon abgesehen kannst du hier sinnvoll mit
Copy'n'Paste arbeiten, da sich die einzelnen Begin-End-Blöcke innerhalb
des Case-Blocks meist sehr ähnlich sind.

Programmieren ist immer ein Aufwand. Lohnt sich aber meistens doch, wenn
man das Resultat mit dem händischen Heraussuchen eines Records aus einer
ellenlangen Tabelle vergleicht.

Lesen Sie weiter auf narkive:
Loading...