MySQL: Altersberechnung [gelöst! :)]

DaPhreak

Primus inter pares
ID: 30143
L
8 Mai 2006
2.418
295
Ich meine, es gab vor einiger Zeit mal einen Thread, wo es darum ging, wie man das Alter am besten berechnen kann, aber ich find ihn nicht mehr. Falls mich jemand darauf stoßen könnte wär's vermutlich schon die "Lösung".


Die Frage ist: Wenn ich Geburtstage in Form von DATE - Feldern gespeichert habe, wie berechne ich jetz das Alter am besten?

Für meine Zwecke wäre es nicht so schlimm, wenn's nicht auf den Tag stimmt, denn ich will eigentlich nur das Durchschnittsalter oder vllt. noch ein Histogramm.

*edit*: DATEDIFF liefert den gleichen Fehler wie DATE_DIFF...

Mein erster Ansatz war mit DATEDIFF zu arbeiten àla:

Code:
SELECT DATEDIFF(CURDATE(), `bday`) FROM `users`;
Das sollte mir das Alter in Tagen ausgeben. Keine sehr schöne Lösung, nur ein erster Ansatz. Eigenartigerweise funktioniert nicht mal das:

Code:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '( CURDATE( ) , `bday` ) FROM `fpms_userdaten`  LIMIT 0, 30' at line 1

Obwohl ich mit MySQL 4.1.22 aktuell genug bin und das Beispiel ausm Manual
Code:
SELECT DATEDIFF('1997-12-31 23:59:59','1997-12-30');
ja auch funktioniert.

Bin ich irgendwie grade massiv blockiert, dass ich nich sehe warum das nich geht?

Zum Vergleich, ein
Code:
SELECT CURDATE(), `bday` FROM `users`;
liefert:
Code:
 CURDATE( )   	  bday
2006-09-14 	1981-04-06
2006-09-14 	1996-12-31
2006-09-14 	1922-01-19

also schon die richtigen Datentypen und das richtige Feld ansich.



Nuja, besser wär's vielleicht eh, gleich mit den Jahren zu rechnen. Also die Differenz der Jahre, falls Tag und Monat schon überschritten sind, sonst eins weniger. Wie krieg ich das am performantesten hin?
 
Zuletzt bearbeitet:
Guck Dir mal in der MySQL-Doku den Kommentar von "Daevid Vincent" vom 4. August 2006 an (ist der vorletzte Kommentar). Der scheint sich genau mit dieser Problematik beschäftigt zu haben.

[edit]

Damn, ist schon zu spät. Sorry. Geht ja um das Alter, nicht um Geburtstag. Aber trotzdem könnte Dir der Kommentar weiterhelfen. Immerhin kann er feststellen, ob der User dieses Jahr schon Geburtstag hatte oder nicht. Also musst Du das ganze nur noch dahin abwandeln, dass es benutzt wird, um die Differenz zwischen den Jahren entsprechend anzupassen (-1 wenn dieses Jahr noch nicht Geburtstag).

Könnte der Fehler btw daher kommen, dass Du DATE_DIFF statt DATEDIFF schreibst?
 
Zuletzt bearbeitet:
Will ich mal net so sein ^^

PHP:
function alter($gebd,$gebm,$geby){  
    $time=time();  
    $akty=date("Y", $time);  
    $aktm=date("m", $time);  
    $aktd=date("d", $time);  
    $alter=$akty-$geby;  
    $v=$aktm-$gebm;  
    if ($v < 0)  
        $alter=$alter-1;  
    if ($v == 0){  
      $d=$aktd-$gebd;  
      if ($d < 0)  
        $alter=$alter-1;  
    }  
    return $alter;  
}
/* Altersberechung ende | Aufruf mit "alter(07,02,1984)"
$teil=explode(".","07.02.1984");
$tag=$teil[0]; //also in diesem Falle 07
$monat=$teil[1]; //hier: 02
$jahr=$teil[2]; //hier: 1984
echo alter($tag,$monat,$jahr);
*/
 
Damn, ist schon zu spät. Sorry. Geht ja um das Alter, nicht um Geburtstag. Aber trotzdem könnte Dir der Kommentar weiterhelfen. Immerhin kann er feststellen, ob der User dieses Jahr schon Geburtstag hatte oder nicht. Also musst Du das ganze nur noch dahin abwandeln, dass es benutzt wird, um die Differenz zwischen den Jahren entsprechend anzupassen (-1 wenn dieses Jahr noch nicht Geburtstag).
Hm, ja. Ich brauch's halt möglichst in einer "MySQL-Formel", damit ich am Ende ein AVG() drumrumsetzen kann... Ich probier noch bissl rum, was zusammenzubasteln.

Könnte der Fehler btw daher kommen, dass Du DATE_DIFF statt DATEDIFF schreibst?
Hab beides probiert, bei beiden der gleiche Fehler...

Will ich mal net so sein ^^
Danke, das ist schon ganz nett, das Problem ist nur, dass das in PHP ist, ich es aber in MySQL brauche. Ich habe halt eine Tabelle mit Benutzern, könnten sehr viele sein und will deren Durchschnittsalter berechnen. Für jeden einzelnen die PHP-Funktion aufzurufen und dann zu mitteln scheint mir zu ineffizient. Es sollte ansich auch mit MySQL gehen.

Könnt ja sein, jemand hat 'ne fertige Lösung dafür ^^



*edit*
Ich habe jetzt unter Benutzung der Geburtstagsformel diese "hässliche" Lösung, die aber zu klappen scheint:

Code:
SELECT (DAYOFYEAR(CURDATE()) < DAYOFYEAR(`bday`)) 
+ EXTRACT(YEAR FROM CURDATE()) - EXTRACT(YEAR FROM `bday`)
FROM `users`

Vorschläge, wie man es schöner machen kann?

Irgendwie zweifle ich grade an der Schaltjahrestauglichkeit davon. Gut, wäre für meinen Anwendungsfall nicht so kritisch, aber halt nich korrekt.
 
Zuletzt bearbeitet:
Wieso findest Du die denn hässlich? Ich bin grad zu einer ähnlichen Lösung gekommen, die auch noch Schaltjahre berücksichtigt:
Code:
SELECT YEAR(NOW()) - YEAR(dob) - IF(DAYOFYEAR(NOW()) < DAYOFYEAR(CONCAT(YEAR(NOW()),DATE_FORMAT(dob, '-%m-%d'))),1,0)
FROM table
Sorry für die Formatierung, aber mehr ist um diese Uhrzeit bei so 'nem wuchtigen Query nicht drin. ;)

Hope that helps...
 
Wieso findest Du die denn hässlich?
Wusst grad nich wie ich das Jahr rausbekomme, YEAR(NOW()) is irgendwie hübscher als EXTRACT(YEAR FROM CURDATE()) ;)

Deine Lösung funktioniert!
Damit habe ich jetzt die folgenden zwei Codeschnipsel:


Berechnung des Durchschnittsalters

Code:
SELECT 
AVG(
  YEAR(NOW()) - YEAR(`bday`) 
  - IF(
       DAYOFYEAR(NOW()) 
    < DAYOFYEAR(CONCAT(YEAR(NOW()),
          DATE_FORMAT(`bday`, '-%m-%d')))
     ,1,0)
) 
AS Age 
FROM `users` 
WHERE `bday` IS NOT NULL;

Ergebnis: Nur eine Zahl.

Berechnung eines Altershistogramms nach Dekaden
Code:
SELECT 
COUNT(`bday`) AS NrUsers,
FLOOR(
   (YEAR(NOW()) - YEAR(`bday`) 
   - IF(
        DAYOFYEAR(NOW()) < 
        DAYOFYEAR(CONCAT(YEAR(NOW()),
            DATE_FORMAT(`bday`, '-%m-%d')))
     ,1,0)
   )
/10) AS Agegroup  
FROM `users` 
WHERE `bday` 
IS NOT NULL 
GROUP BY Agegroup 
ORDER BY Agegroup;

Ergebnis: Tabelle der Form:
Code:
NrUsers|Agegroup
2|0
10|1
20|2
30|3
20|4
10|5
...

Wobei Agegroup = 0 bedeutet von 0 bis 9, Agegroup = 1 von 10 bis 19 usw. Achtung: Wenn es in einer Dekade gar keine Leute gibt, fehlt die Zeile.

Das ganze funktioniert, wenn man eine Tabelle `users` mit dem Feld `bday` vom Typ DATE hat, welches die Geburtstage speichert. NULL bedeutet dabei, dass der User sein Geburtstag nicht angegeben hat.


Vielleicht wäre das ja was für's Archiv hier im Forum. Wenn nicht, lassen wir's eben einfach so stehen. ;)


Vielen lieben Dank nochmal für die Hilfe!


P.S.: Hoffe ich hab beim Formatieren jetzt die Klammern ned versaut *g*
 
Zuletzt bearbeitet: