Forum: PC-Programmierung MySQL Altersabfragen aus Geburtsdaten, stehe voll auf dem Schlauch


von Jens Plappert (Gast)


Lesenswert?

Hallo alle miteinander,

Ich möchte für eine Statistik verschiedene Altersbereiche der Benutzer 
meiner Anwendung auswerten (also so etwas wie "Jungen, 13-17 Jahre" usw.

Mein bisheriger Code schaut so aus (Abfrage aus PHP):
1
           
2
AND User.Geburtstag BETWEEN DATE_SUB(NOW(),INTERVAL ".$To." YEAR) 
3
AND DATE_SUB(NOW(),INTERVAL ".$From." YEAR)

Dabei wäre jetzt $From eben die 13 und $To die 17.
Ich habe mittlerweile festgestellt, dass da was nicht sitmmt, weil so 
einige Leute durch das "Raster" fallen und nirgens auftauchen, bin 
jedoch zu noch keiner funktionierenden Lösung gekommen.

Ich hatte schon die Idee, dass man ja 1 Jahr lang sein Alter hat und 363 
Tage addiert bzw abgezogen, aber das war auch nicht richtig (oder ich 
hatte einen Fehler in meiner Query.

Ich weiss dass es eigentlich Pipieinfach sein müsste, aber ich stehe 
gerade so dermassen auf dem Schlauch und drehe mich im Kreis, dass es 
mein Hirn total blockiert.

Würde mich über ein wenig Input freuen, damit ich das Modul dieses WE 
noch fertig stellen kann.

Hoffe es findet sich jemand der mir hilft.

Vielen Dank!

von (prx) A. K. (prx)


Lesenswert?

Wenns nicht grad die Weltbevölkerung betrifft würde ich (heutzutage) 
erst einmal mit YEAR(User.Geburtstag) aus dem Datum eine Zahl machen.

von Jens plappert (Gast)


Lesenswert?

Dann wären aber alle 1990 geborene. Gleich alt, egal ob sie schon 
Geburtstag hatten oder nicht.

von Chris R. (hownottobeseen)


Lesenswert?

Hi,

die MySQL-Referenz hat schon was auf dem silbernen Tablett:

https://dev.mysql.com/doc/refman/5.0/en/date-calculations.html

... WHERE TIMESTAMPDIFF(YEAR, User.Geburtstag, CURDATE()) BETWEEN ? AND 
?

achja: packe nie und nimmer Parameter für SQL-Statements direkt in 
Statements!
Verwende Platzhalter (hier: ?) und arbeite mit Prepare.

Viele Grüße

Chris

von Jens plappert (Gast)


Lesenswert?

Vielen Dank für die Antwort, werde mir das mal genauer anschauen. Wieso 
sollte man die Parameter nicht ins State schreiben ( habe vorher 
natürlich die Daten validiert)

von Andreas G. (andreasgf)


Lesenswert?

Jens plappert schrieb:
> Wieso
> sollte man die Parameter nicht ins State schreiben ( habe vorher
> natürlich die Daten validiert)

http://de.wikipedia.org/wiki/SQL-Injection

von Jens P. (Gast)


Lesenswert?

Ok, was hier natürlich in meinem Codeschnipsel nicht ersichtlich ist:

Bei mir gehen nur Daten in die Query, die vorher mit 
mysqli_real_escap_string oder intval() "gecheckt" wurden. Trotzdem 
schlecht?

von Philipp K. (philipp_k59)


Lesenswert?

Wenn das jetzt nich für Tage genau gelten sollte sondern nur für das 
Ganze Jahr.. so das die statistik wenn morgen jemand Geburtstag hätte 
nicht wieder anders aussieht.

Könnte fixer als Between sein.

Ungeprüft:
 WHERE YEAR(GEBURTSTAG) < YEAR(CURDATE())-ALTERMIN AND YEAR(GEBURTSTAG) 
>YEAR(CURDATE())-ALTERMAX

von Jens P. (Gast)


Lesenswert?

Ich habe es jetzt mit der weiter oben genannten Abfrage (mit Between) 
gelöst, das ist auch ausreichend performant bei um die 100 Benutzern.

Vielen dank an alle für die Tipps und Hinweise!

von Chris R. (hownottobeseen)


Lesenswert?

Jens Plappert schrieb:
> Bei mir gehen nur Daten in die Query, die vorher mit
> mysqli_real_escap_string oder intval() "gecheckt" wurden. Trotzdem
> schlecht?

wenn ich mich richtig erinnere, gab es auch mit den Escape-Methoden 
mögliche Injections.

Nimm einfach Prepared statements, damit bist du garantiert auf der 
sicheren Seite und das Statement muss bei mehreren gleichartigen 
Abfragen (z.B. mehrere Altersgruppen) nur einmal kompiliert werden.

von Philipp K. (philipp_k59)


Angehängte Dateien:

Lesenswert?

Mich hat das weil es pratisch ist nicht in ruhe gelassen und habe mir 
das nochmal angeschaut,als Anhang mal eine Idee für einen automatischen 
3 Jahres Interval auf die ganze Tabelle ohne WHERE automatisch sortiert.

Bedarf noch einer Ergebnisprüfung, sieht schonmal gut aus.

SELECT COUNT(*) AS ANZAHL ,(YEAR(NOW())-YEAR(MIN(user_birthdate)))AS 
ALTERjahr,YEAR(MIN(user_birthdate))AS VON,YEAR(MAX(user_birthdate))AS 
BIS, ROUND(YEAR(user_BIRTHDATE)/3) AS jahresindex FROM `users` GROUP By 
jahresindex

von guest (Gast)


Lesenswert?

Die Variante mit dem 'TIMESTAMPDIFF' führt leider zu einem 'full table 
scan'. Bei 100 Eintägen mag das noch kein Problem sein, wenn es mal mehr 
werden schon.

Hab grad kein MySQL zum testen da, aber die Ursprungsvariante könnte an 
einem falschen Datentyp scheitern. Eventuell reicht es NOW() jeweils 
durch CURDATE() zu ersetzen. Ansonsten um den Aufruf von DATE_SUB() noch 
ein CAST() auf den für das Feld User.Geburtstag verwendeten Datentyp.

von Sven B. (scummos)


Lesenswert?

Jens Plappert schrieb:
> Bei mir gehen nur Daten in die Query, die vorher mit
> mysqli_real_escap_string oder intval() "gecheckt" wurden. Trotzdem
> schlecht?

Das bringt dir an der Stelle kaum was, weil du ja nichtmal 
Anführungszeichen um den Wert drum hast. Benutz' prepared statements.

von Karl Käfer (Gast)


Lesenswert?

Hallo Jens,

Jens Plappert schrieb:
> Ich möchte für eine Statistik verschiedene Altersbereiche der Benutzer
> meiner Anwendung auswerten (also so etwas wie "Jungen, 13-17 Jahre" usw.
>
> Mein bisheriger Code schaut so aus (Abfrage aus PHP):
>
>
1
> AND User.Geburtstag BETWEEN DATE_SUB(NOW(),INTERVAL ".$To." YEAR)
2
> AND DATE_SUB(NOW(),INTERVAL ".$From." YEAR)
3
>
>
> Dabei wäre jetzt $From eben die 13 und $To die 17.
> Ich habe mittlerweile festgestellt, dass da was nicht sitmmt, weil so
> einige Leute durch das "Raster" fallen und nirgens auftauchen, bin
> jedoch zu noch keiner funktionierenden Lösung gekommen.

Möglicherweise ist es bei MySQL nicht so, aber bei anderen DBMS muß der 
erste Parameter für BETWEEN unbedingt vor dem zweiten liegen.

HTH,
Karl

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.