Hallo,
ich hätte eine Frage:
Ich habe eine Abfrage erstellt, die in einem ungebundenen Feld das Alter von Personen berechnet. Die Altersberechnung sieht wie folgt aus:
Alter: Jahr((Jetzt()+1)-[Geburtsdatum])-1900
Wenn ich nun für das Alter als Kriterium Parameterfragen eingebe:
Zwischen [Alter von] Und [Alter bis]
dann erhalte ich z.B. bei Alter von 15 bis 25 auch Kinder im Alter von 2 Jahren (aber nicht von 1 oder z.B. 5 Jahren).
Wenn ich die Kriterien direkt eingebe, also:
Zwischen 15 Und 25
dann ist die Ausgabe richtig.
Weiß vielleicht jemand was ich falsch mache bei der Parametereingabe?
compinaut
Hallo,
wenn man jetzt die Abfrage (SQL) sehen würde, könnte ja helfen.
Aber wie will man was prüfen, das man nicht sieht?
Moin,
die Ermittlung des Alters ist schon mal fehlerträchtig -> s. http://www.donkarl.com?FAQ2.7
der falsche Rückgabewert deutet auf Verwendung von String statt Zahl hin. Genaueres lässt sich aber nur mit dem SQL-Statement analysieren, wie Klaus schon gepostet hat.
Hallo,
schreib mal:
PersonenAlter: Val(Jahr((Datum()+1)-[Geburtsdatum])-1900)
und/oder
Zwischen Val([Alter von]) Und Val([Alter bis])
ZitatWeiß vielleicht jemand was ich falsch mache bei der Parametereingabe?
Man kann nur Werte als Parameter übergeben, keine Ausdrücke (Wert + Operator). Du könntest aber von-Wert und bis-Wert separat als Parameter übergeben, was auch sinnvoll ist, denn 1 Jahr als Altersklasse ist auch ein Zeitraum und lässt sich über von-bis abbilden.
Ansonsten müsste man Filter/SQL-Anweisung dynamisch per VBA zusammensetzen
Deine Rechnung ist aber an sich auch recht berechnungsintensiv.
WHERE Geburtsdatum BETWEEN #1/1/1992# AND #12/31/2002#
Bei einem solchen Filter würde Dich die Maschine leben, es wäre zudem eine Indexnutzung möglich.
Hier könnte man gleichlautend auf das heutige Datum und das daraus resultierende Alter eingehen.
Hallo,
ich habe das mal getestet, die Altersformel war mir auch unbekannt, ist aber nach meinen Tests richtig. Es wird auch eine Zahl ausgegeben und das Zwischen ... Und Bis funktioniert bei meinen Tests auch richtig.
Daher ja die Frage nach der Abfragte.
Hallo,
zu:
ZitatMan kann nur Werte als Parameter übergeben, keine Ausdrücke (Wert + Operator).
Das stimmt an sich, trifft aber auf das Problem hier nicht zu.
Es wird hier der "Ausdruck" (Parameter "[Alter von]") mit einer Funktion bearbeitet
z. B. als Test:
SELECT Aufgaben.*, Year([Fälligkeitsdatum]) AS J
FROM Aufgaben
WHERE (((Year([Fälligkeitsdatum])) Between Val([Jahr Von]) And Val([Jahr bis])));
zum Problem:
vielleicht steht auch die Format-Eigenschaft der Abfragespalte auf unpassenden Eintrag...
Hallo,
diese Abfrage funktioniert bei meinen Tests völlig ohne Probleme.
Ohne Val oder anderen Anpassungen.
SELECT Geburtsdatum, Year((Now()+1)-[Geburtsdatum])-1900 AS [Alter]
FROM Namenstabelle
WHERE Year((Now()+1)-[Geburtsdatum])-1900 Between [von] And [bis]
Es müsste eine 2 hinzuaddiert werden, um den Offset 30. Dez 1899 auszugleichen, denn sonst wäre man am Geburtstag selbst -1 Jahre alt.
WHERE Year((Now()+1)-[Geburtsdatum])-1900 Between [von] And [bis]
Wenn man vollständig testet, wird man auch Fehler finden. Ich unterstelle mal, dass man mit Funktionieren auch ein fehlerfreies Ergebnis meint.
- Date() - Geburtsdatum ergibt eine Tagesdifferenz (warum Now, also inkl. Zeitanteil?)
- Darauf Year angewandt, das als Argument ein Datum braucht, erzeugt ein CDate(Date() - Geburtsdatum).
- Dieses intern erzeugte Datum hat mit dem Geburtsdatum nicht mehr viel gemeinsam, ein Year darauf ist vergleichbar unscharf, als wenn man die Tagesdifferenz durch 365 oder 365,25 teilt, einfach weil man nicht berücksichtigen kann, wieviele Schalttage es wirklich zwischen Geburtstag und Heute gibt. Korrekturversuche mit Val und Hilfszahlen laufen da ins Leere.
Ergo: Diese Altersberechnung in der gezeigten Form hat ein systematisches Problem.
Stimmt - ab 8 Jahren treten Fehler auf. :( Ich verwende diese Funktion zur Alterberechnung.'// Age[years] could be calculated by dividing a difference of two Dates by
'// about 365.25, but this will be wrong by a day or so from time to time
'// (especially since 1900 and 2100 are not leap years, but 2000 is). "Simple"
'// comparision of the TestDate against the BirthDate does yield the desired
'// "common sense" age.
Public Function Age(ByVal BirthDate, Optional ByVal TestDate)
Dim DayBirth%, DayTest%
Dim MonthBirth%, MonthTest%
Dim YearBirth%, YearTest%
If IsDate(BirthDate) Then
If Not IsDate(TestDate) Then
TestDate = Date
End If
'// Ignore TestDate before BirthDate
If TestDate > BirthDate Then
YearBirth = Year(BirthDate)
MonthBirth = Month(BirthDate)
DayBirth = Day(BirthDate)
YearTest = Year(TestDate)
MonthTest = Month(TestDate)
DayTest = Day(TestDate)
'// Code algorithm this way so anyone can understand what is going on
'// here.
If MonthTest > MonthBirth Then '// Any month past BirthDate
Age = YearTest - YearBirth
ElseIf MonthTest < MonthBirth Then '// Any month before BirthDate
Age = YearTest - YearBirth - 1
ElseIf DayTest >= DayBirth Then '// On or after BirthDate
Age = YearTest - YearBirth
Else
Age = YearTest - YearBirth - 1
End If
Else
Age = Null
End If
End If
End Function
Hallo,
ich hätte der mir unbekannten Formel nicht so vertrauen sollen. Und meine Tests waren auch viel zu oberflächlich.
Ich verwende schon seit Jahren die Altersformel aus
FAQ 2.7 Alter ermitteln (http://www.donkarl.com?FAQ2.7)
Was dann zu dieser Abfrage führt:
SELECT Geburtsdatum,
DateDiff("yyyy",[Geburtsdatum],Date())+(Format(Date(),"mmdd")<Format([Geburtsdatum],"mmdd")) AS [LebensAlter]
FROM Namenstabelle
WHERE DateDiff("yyyy",[Geburtsdatum],Date())+(Format(Date(),"mmdd")<Format([Geburtsdatum],"mmdd")) Between [von] And [bis]
@Lachtaube
Gibt es einen Grund statt der FAQ 2.7 die von Dir gezeigte doch recht aufwendige Funktion zu verwenden ?
Meine Version ist mehr als doppelt so schnell.
Die von Nouba gezeigte Funktion ist nicht aufwändig. Sie ist im Code etwas länger, verwendet aber nur simpelste Rechnungen und logische Prüfungen. Zusätzlich wird da geprüft, ob überhaupt ein Date-Wert als Geburtsdatum übergeben wird. Das kann bei VBA schnell mal passieren, aus einer Datenbanktabelle heraus sicher nicht. Auch beherrscht SQL den Umgang mit NULL, bei VBA muss man da aufpassen.
Insgesamt leitet sich ein Aufwand von der Summe der Berechnungen ab. Eine VBA-Funktion oder gar eine eigendefinierte Funktion, die sich eines anderem Objektes bedienen müssen als dem eigentlichen SQL-Sprachumfang, sind da tendenziell schlechter gestellt. Es wird sich aber auch der Einzelaufwand pro verwendeter Einzelanweisung und die Summe daraus bemerkbar machen.
In der Praxis wird sich die benötigte Zeit auch bei großen Datenmengen bei der Altersberechnung im SELECT-Teil eher nicht erheblich spürbar unterscheiden, wenn man die Varianten gegenüberstellt.
Wenn man aber Aufwand und Zeit beim Filtern betrachtet, stellen sich ganz andere Fragen (neben der Korrektheit der Ergebnisse):
WHERE Year((Now()+1)-[Geburtsdatum])-1900 Between [von] And [bis]
Hier wird eine Berechnung auf das Tabellenfeld ausgeführt. Bei 1000 Datensätzen sind das 1000 Berechnungen. Bei anderen Altersberechnungen, aber der gleichen Filterung, wäre es genau so => der Einzelaufwand wird vervielfacht.
Ebenso wesentlich: Bei der Filterung auf ein berechnetes Feld ist eine Indexnutzung nicht möglich.
Gegenvariante für Filterung: Man lässt das Feld Geburtsdatum so wie es ist und berechnet dafür die Grenzen für die Filterung. Letztere sind einmalig zu rechnen und verbrauchen minimalst Zeit, auch wenn die Berechnung etwas aufwändiger daherkommen sollte (was im gezeigten Fall noch nicht der Fall ist):
SELECT
*
FROM
TabelleX
WHERE
Geburtsdatum BETWEEN DateSerial(Year(Date() - [VonAlter] + 1), Month(Date()), Day(Date() - 1)
AND
DateSerial(Year(Date() - [BisAlter]), Month(Date()), Day(Date())