Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Table nach Datum filtern (https://www.delphipraxis.net/173373-table-nach-datum-filtern.html)

jedi 20. Feb 2013 16:47

Datenbank: ACCESS • Version: 2007 • Zugriff über: DAO

Table nach Datum filtern
 
Ich habe nun seit mehreren Tagen gesucht, die gefundenen Beispiele ausprobiert und keine Lösung gefunden,
obwohl dieses Thema schon oft behandelt wurde.

Ich will eine Mitglieder-Datenbank anhand des Geburtstages in Erwachsene und Jugendliche filtern.
Das entsprechende Feld in der Tabelle habe ich mit
Code:
FieldDef.Add('Geb-Tag'), ftDate, 0, False)
angelegt. Vorhandene Testdaten sind Geburtstage 02.04.1950, 03.08.1997 und als Test ein Geburtstag in der Zukunft 05.06.2013.
Wenn ich die Daten über einen Filter ansprechen will, schlägt alles gefundene fehl.
Die einzige Version, die bei mir funktioniert, ist
Code:
MitgliederTable.Filter := 'Geb_Tag = Date()' // oder
MitgliederTable.Filter := 'Geb_Tag < Date()' // oder
MitgliederTable.Filter := 'Geb_Tag > Date()'
Hier wird alles richtig ausgewertet und die Auswahl vor bzw. nach Date() auch richtig ausgeführt.

Nun muss ich aber statt Date() ein direktes bzw. errechnetes Datum einsetzen, und da liegt das Problem:
Code:
MitgliederTable.Filter := 'Geb_Tag = 01.01.1995' // Syntaxfehler in Zahl in Abfrageausdruck 'Geb_Tag = 01.01.1995' aufgetreten
MitgliederTable.Filter := 'Geb_Tag = 01/01/1995' // keine Datensätze, ist i.O.
MitgliederTable.Filter := 'Geb_Tag < 01/01/1995' // keine Datensatz
MitgliederTable.Filter := 'Geb_Tag > 01/01/1995' // Anzeige 3 Datensätze
Wer kann mir helfen bzw. wo liegt der Fehler in meiner Denkweise und wie könnte eine Lösung aussehen?

Danke für Eure Hilfe

p80286 20. Feb 2013 16:52

AW: Table nach Datum filtern
 
Wenn man mit ACCESS direkt arbeitet wird das Datum von # eingeschlossen also
Code:
Gebdatum=#01.01.2012#
versuch es doch einmal so.

Gruß
K-H

jedi 20. Feb 2013 16:58

AW: Table nach Datum filtern
 
Danke, aber Fehlermeldung:

Syntaxfehler in Datum in Abfrageausdruck 'Geb_Tag < #01.01.1994#' aufgetreten.

Nach Umstellung auf: 'Geb_Tag < #01/01/1994#' funktioniert alles!

Nachmals besten Dank!

sx2008 20. Feb 2013 17:14

AW: Table nach Datum filtern
 
Man sollte Felder nicht im Sourcecode mit
Delphi-Quellcode:
FieldDef.Add()
anlegen, sondern entscheidend ist, dass das Feld in der Tabelle mit dem richtigen Datentyp vorhanden ist und die Testdatensätze entsprechend befüllt sind.

Dann sollte man auf keinen Feld Feldnamen mit Bindestrich ('Geb-Tag') verwenden, weil das als Minuszeichen interpretiert werden kann. Unterstriche sind dagegen in Ordnung.

Datumswerte im Filter-Property sind immer etwas tricky weil man das Datum als String angeben muss und die Schreibweise von den lokalen Einstellungen und/oder von den Eigenheiten der Datenbank abhängt.
Die Schreibweise mit den beiden # ist spezifisch für MS-Access und funktioniert z.B. nicht beim MS SQL-Server.

Wenn man das Event
Delphi-Quellcode:
OnFilterRecord
benützt, dann kann man sich diese Unsicherheit sparen:
Delphi-Quellcode:
procedure TForm1.MitgliederTableFilterRecord(DataSet: TDataSet; var Accept: Boolean);
var
  d : TDateTime;
begin
  d := SysUtils.Date - 18 * 365; // grob 18 Jahre in die Vergangenheit
  if DataSet.FieldByName('Geb_Tag').AsDateTime >= d then
     Accept := True
  else
     Accept := False
end;

jedi 20. Feb 2013 17:41

AW: Table nach Datum filtern
 
@SX2008
Danke für die Hinweise, eine Frage dazu:

Anlegen der Tabelle:
Code:
FieldDefs.Add()
verwende ich, da jährlich automatisch eine neue Tabelle vom Programm erzeugt werden muss (Anwender hat kein Access).
Danach werden nur ausgewählte Daten der alten Tabelle an die neue Tabelle übergeben, da Informationen über Beiträge u.ä. jahresbezogen
erfasst werde.
Welche (besseren) Möglichkeiten zum Anlegen der Tabellen gibt es?

Bindestrich - Unterstrich ist mir bekannt. Ich verwende generell Unterstriche.

Code:
OnFilterRecord
werde ich mir mal genauer ansehen, habe ich bisher kaum verwendet.
Die Anwendung könnte mir einige Zeilen Quelltext sparen!

Bernhard Geyer 20. Feb 2013 18:02

AW: Table nach Datum filtern
 
Zitat:

Zitat von sx2008 (Beitrag 1204503)
Wenn man das Event
Delphi-Quellcode:
OnFilterRecord
benützt, dann kann man sich diese Unsicherheit sparen

Und sich dann wundern wieso die Anwendung so langsam ist. Da der Filter Lokal ausgeführt wird werden alle Daten der Tabelle zum Client übertragen und ausgewertet. Bei einer Tabelle mit 5 GB an Datenvolumen kann es Dauern obwohl Index vorhanden ist und nur wenige Datensätze passen.

Sinnvoll ist es hier sich mit SQL vertraut zu machen. Diese als SQL-Statement mit parameter zu implementieren ist schnell und auch noch relativ unabhängig vom DBMS.

sx2008 20. Feb 2013 19:39

AW: Table nach Datum filtern
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1204513)
Und sich dann wundern wieso die Anwendung so langsam ist. ... Sinnvoll ist es hier sich mit SQL vertraut zu machen.

Ich wollte den TE nicht gleich überfordern.
Eine parametrisierte SQL-Abfrage ist technisch sicher die schnellste und sauberste Lösung.
Wobei, wie viele Mitglieder kann so ein Verein schon haben? Bei < 1000 Mitgliedern ist so ein lokaler Filter kein Problem.

Zitat:

Zitat von jedi (Beitrag 1204509)
Welche (besseren) Möglichkeiten zum Anlegen der Tabellen gibt es?

Also normalerweise legt man in der Anwendung keine Tabellen an, sondern man gibt eine leere Datenbank, die aber schon alle Tabellen enthält bei der Installation mit der Anwendung mit.
Man sollte die Datenbank so bauen, dass die Struktur der Tabellen, Felder, Views usw. sich möglichst nicht mehr ändert.

Wenn man z.B. Mitgliedsbeträge pro Jahr erfassen möchte, dann legt man nicht für jedes Jahr eine neue Tabelle an, sondern man speichert alles in einer Tabelle:
Code:
MitgliedNr | Jahr | ZahlDatum
==============================
          1| 2012 | 13.01.2012
          2  2012 | 25.02.2012
          3| 2012 | 08.05.2012
          2| 2013 | 19.02.2013
          3| 2013 | 29.12.2012
Wie man sieht hat Mitglied 1 für das Jahr 2013 noch nicht bezahlt.
Wenn man z.B. wissen möchte, wer im aktuellen Jahr noch nicht gezahlt hat, dann muss man die Betragstabelle mit der Mitgliedertabelle verknüpfen.
Spätestens jetzt kommt man nicht drumrum, sich in SQL einzuarbeiten.

SQL-Code:
-- hole alle Datensätze aus der Mitglieds-Tabelle für die es keinen passenden Datensatz
-- in der Betrags-Tabelle gibt und berücksichte dabei nur das Jahr 2013
SELECT MitgliederTable.* FROM
MitgliederTable
WHERE NOT EXISTS (SELECT * FROM BeitragsTable WHERE BeitragsTable.MitgliedsNr=MitgliederTable.MitgliedsNr AND BeitragsTable.Jahr=2013)

Bernhard Geyer 20. Feb 2013 19:48

AW: Table nach Datum filtern
 
Zitat:

Zitat von sx2008 (Beitrag 1204525)
Ich wollte den TE nicht gleich überfordern.

Ok. Genehmigt.

Zitat:

Zitat von sx2008 (Beitrag 1204525)
Eine parametrisierte SQL-Abfrage ist technisch sicher die schnellste und sauberste Lösung.
Wobei, wie viele Mitglieder kann so ein Verein schon haben? Bei < 1000 Mitgliedern ist so ein lokaler Filter kein Problem.

In meiner Access-Vereinsdatenbank lege ich für obige Anforderungen immer Views an die ich dann verwende.

jedi 21. Feb 2013 07:14

AW: Table nach Datum filtern
 
@SX2008

An die Möglichkeit mit einer verknüpften Tabelle zu arbeiten hatte ich in am Anfang auch angedacht, bin aber aus folgendem Grund davon abgekommen:
Die Mitgliederanzahl des Vereinsliegt bei ca. 280 - 300. Die Tabelle der Mitglieder besteht aus 16, die der jahresbezogenen Daten aus 14 Feldern. Im ersten jahr habe ich also 2 Tabellen mit je ca. 300 Datensätzen. Im den folgenden Jahren erweitert sich die Tabelle der jahresbezogenen Daten um jeweils weitere 300 Datensätze, so dass nach wenigen Jahren ein enormer Zuwachs an Daten anfällt, der zu längeren Zeiten bei der Auswertung führen könnte. Das war mein Denkansatz. Wenn der falsch ist, nehme ich gern andere Vorschläge an. Ich arbeite mich ja auch erst noch in die Programmierung ein.

jobo 21. Feb 2013 07:48

AW: Table nach Datum filtern
 
Man würde niemals "gleiche" Daten in verschiedenen Tabellen sammeln. Das sind grundlegende Fragen des Datenbank Designs (Stichwort Normalisierung).
Was sind nun gleiche Daten?
Bspw. wäre es falsch Vereinsmitglieder in 2 Tabellen "JUGENDLICHE" und "ERWACHSENE" zu speichern, vielleicht noch eine 3. Tabelle "ELTERN" (keine Mitglieder). Statt dessen alle Personen in eine Tabelle und über ein Feld Kategorien bilden. Die Unterscheidung Jugendliche/Erwachse würde über das gespeicherte Geburtsdatum und das daraus zu errechnende aktuelle Alter abgebildet.
In Deinem Fall ist nicht zu erwarten, dass es mittelfristig Performanceprobleme gibt. Für die Einschränkung der Datenmenge bieten sich wie bereits gesagt Views an, die bspw. nur aktive, zahlende, neue, ausgeschiedene, whatever, .. Mitglieder liefern.

jedi 21. Feb 2013 10:08

AW: Table nach Datum filtern
 
@jobo
Genau so ist mein Vorgehen.
Ich habe alle Daten in einer einzigen Tabelle und wähle die entsprechenden Altersgruppen über Filter (Berechnung aus Feld Geb_Tag und Diff zum 31.12., da Stichtag der Altersgruppe immer der 1.1. des laufenden Jahres ist) zur Anzeige und Druck aus.
Da ich wie schon angeführt viele jahresbezogene Daten habe will ich selbst die jahresbezogenen Daten in keine Zusatztabelle auslagern, sondern erstelle am Jahresende automatisch eine neue Mitgliedertabelle für das laufende Jahr durch Übernahme der Mitgliederdaten ohne jahresbezogene Daten z.b Mitglieder_2010, Mitglieder_2011 usw.. Somit arbeite ich immer nur mit dem aktuellen Mitgliederstand, kann jederzeit aber auf alte Daten zurückgreifen.

p80286 21. Feb 2013 11:09

AW: Table nach Datum filtern
 
Zu meinem Verständnis,
Du hast eine Tabelle, in der alle Daten enthalten sind.
Für jedes Kalenderjahr befindet sich in dieser Tabelle ein volltändiger Mitgliedersatz.

Falls dies so ist,
dann ist das Design schon suboptimal.

aus der hohlen Hand
Deine Datenbank sollte mindestens zwei Tabellen haben,
a) Mitglieder
b) Mitgliedsdaten

wobei in der Mitglieder-Tabelle mindestens Name und Eintritts und Austrittsdatum enthalten sein sollten. Da ist es völlig unproblematisch festzustellen wer am 4.5.2009, vom Janur bis Juni 2008
oder wann auch immer Mitglied war.

Gruß
K-H

jedi 21. Feb 2013 12:38

AW: Table nach Datum filtern
 
@p80286
Hallo,
so ähnlich war mein 1. Ansatz.
Ein paar weitere Informationen dazu, warum ich diesen Ansatz dann allerdings wieder verworfen habe:

(meine Denkweise kann natürlich auch völlig falsch sein!)

Ich muss die Mitgliedertabelle auch jährlich wieder an eine neue Zusatzdatentabelle anhängen, da sich 80% der dort geführten Daten jährlich ändern (entsprechend der jährlich beantragten Berechtigungen ändern sich die Art, Höhe und Bezeichnung des Mitgliedsbeitrages, die Ausstellungsnummern und das Ausstellungsdatum der Berechtigungsausweise und ähnliche Daten. Da ich diese Daten aber bis zu 5 Jahre zurück weiterhin vorhalten muss, kann ich diese Tabelle also nicht überschreiben sondern muss eine neue Tabelle erstellen (oder ein weiteres Zuordnungsjahr in der Tabelle dann einfügen um die Daten getrennt zu halten). Damit wird diese Tabelle dann aber sehr umfangreich.
Deshalb war mein Ansatz, gleich alle Daten in einer Tabelle zu führen, die dann allerdings jährlich auch neu erstellt werden muss.

sx2008 21. Feb 2013 14:44

AW: Table nach Datum filtern
 
Zitat:

Zitat von jedi (Beitrag 1204597)
(meine Denkweise kann natürlich auch völlig falsch sein!)

Ja :) dir fehlt noch etwas Erfahrung im Datenbankdesign.
Also, wenn es in einer Datenbank zwei (oder mehr) Tabellen gibt, die in ihren Feldern komplett übereinstimmen, dann ist etwas faul am Design.
Denn es ist ja jederzeit möglich, die Datensätze aus den beiden Tabellen in eine einzige Tabelle zu verfrachten und zusätzlich ein weiteres Datenfeld aufzunehmen.

Es gibt zu dieser Regel eigentlich nur eine Ausnahme:
Performanceprobleme - bei hoher Datenmenge im GByte-Bereich muss man manche Tabellen in mehrere Tabellen zerlegen.
Man nennt das horizontale Partitionierung und man braucht das nur bei wirklich sehr vielen Datensätzen.


Auf dein Problem bezogen heisst das du braucht z.Zt. min. 3 Tabellen
* Mitglieder (pro Mitglied ein Datensatz)
* Beitraege (pro Mitglied und Jahr ein Datensatz)
* Konditionen (pro Jahr ein Datensatz)

Mit SQL ist es kein Problem die Daten die Daten aus mehreren Tabellen zu verknüpfen und unerwünschte Datensätze (z.B. alles was nicht zum Jahr 2013 gehört) auszufiltern.

Über die Datenmenge brauchst du dir keine Gedanken machen.
Es ist z.B. kein Problem in einer Access-Datenbank (150MB) alle Orte (~40000) und alle Strassen (~1,4 Mio) von Deutschland zu speichern und jede Adresse innerhalb 0,8s zu finden.

p80286 21. Feb 2013 14:54

AW: Table nach Datum filtern
 
Da gäbe es mehrere Möglichkeiten, es kommt halt auf die Daten an
Mitgliederdaten:
Code:
ID
PersID
von
bis
Eigenschaft1,Eigenschaft2,.....
oder aber Du hast eine Tabelle mit den "Eigenschaften"
und verknüpfst Mitglieder und Eigenschaften über eine eigene Tabelle
Code:
MitgliederTable
MitgliedID
Name,Vorname, Adresse.....


LinkTable
ID
MitgliedID
EigenschaftID
von
bis

EgenschaftenTable
EigenschaftID
Eigenschaft
kommt natürlich auf deine konkreten Daten an, ggf sind noch ein paar Tabellen nötig, aber Dein jetziger Ansatz führt früher oder später in eine böse Sackgasse.
(das mit der "Normalisierung" war kein Scherz!)

Gruß
K-H

jedi 21. Feb 2013 16:12

AW: Table nach Datum filtern
 
Zitat:

Ja dir fehlt noch etwas Erfahrung im Datenbankdesign.
Das stimmt!
@sx2008
@p80286
Ich glaube auch das Problem in meiner Denkweise gefunden zu haben. Der Grundgedanke bei der Entwicklung war einfach nur: Verwaltung der Daten für "jetzt", nächstes Jahr einfach Tabelle kopieren und neue Daten hinzufügen. Somit verwende ich unter einem "Dach" (Datenbank) pro Jahr eine Tabelle, die keinen Bezug zur Tabelle des Vorjahres hat. Für einen "echten" Datenbankprogrammierer vermutlich eine unmögliche Situation, für mich aber ein Anfang. Ich werde mich bessern!
Für mich war die Datenbank einfach nur ein "Container" der einzelnen Tabellen, während die "jährliche Tabelle" für mich die eigentliche "Datenbank" dargestellt hat. Deshalb sind meine Betrachtungen immer in Richrung "Tabelle" gegangen und nicht in Richtung übergreifende Datenbank.

Da das Problem mit dem Datum nun erst einmal gelöst ist läuft mein Programm entsprechend meiner Vorstellungen und ich kann mich von meiner Access-Version verabschieden (Dort habe ich die Datenbank einfach jedes Jahr kopiert und unter neuem Namen gespeichert, deshalb vermutlich auch meine denkweise in Bezug einer neuen Tabelle pro Jahr!).
Ich werde mich allerdings jetzt (parallel zur jetzigen Variante) mit Euren Lösungsansätzen mal ausführlich beschäftigen, mein "Datenbankverständnis" etwas auffrischen und das Programm umgestalten und hoffe bei weiteren Fragen auf Eure Hilfe. Eure Beiträge haben mir wirklich sehr geholfen.

Nochmals besten Dank für die Unterstützung!


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:52 Uhr.

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