Melvin Cowznofski: Geburtstage der letzten und kommenden 3 Tage

Beitrag lesen

Hallo,

ich habe heute Früh irgendetwas bzgl. MySQL gegoogelt und bin dabei zufällig auf eine Seite gestoßen, wo jemand das Problem hatte, aus einer Tabelle einer MySQL Datenbank, in der es eine Spalte mit Geburtstagen im DATE Format gibt, sich alle Leute anzeigen lassen zu wollen, deren Geburtstag zwischen den letzten 3 Tagen und den kommenden 3 Tagen liegt. (Ich gehe davon aus, dass durch eine Eingabevalidierung sichergestellt ist, dass in der Geburtstagsspalte ein Datum aus der Vergangenheit stehen _muss_!)

Ich selbst brauche so was momentan nicht aber mich hat es trotzdem gereizt, mich mit dieser Aufgabe zu beschäftigen. Nach ca. 10 Stunden Googeln, Manual Lesen und meist erfolglosem Herumprobieren habe ich nun nicht nur brennende Augen, sondern auch ein Ergebnis, das ich hier vorstellen möchte. Einerseits, weil ich da Fragen dazu habe, andererseits, weil ich gerne wissen würde, was Ihr von meiner Lösung haltet. Kann ja leicht möglich sein, dass es eine bessere/simplere Lösung gibt.

Nach längerem Googeln fand ich als erste brauchbare Idee diese Lösung. Hier stehe ich leider vor dem Problem, dass ich auch selbst nach stundenlangem Nachdenken den Block […]AS days\_to\_birthday nicht mal ansatzweise verstehe.

Also habe ich weitergesucht und fand dann auf dieser Seite folgenden Lösungsvorschlag für diese Art von Fragestellung:

This was a little tricky, but here is my solution:

SELECT  
    birthday,  
    -- Shift the birthday into the current year  
    CAST(CONCAT(YEAR(NOW()), '-', MONTH(birthday), '-', DAY(birthday)) AS DATE) AS BirthdayInCurrentYear  
FROM Club  
WHERE CAST(CONCAT(YEAR(NOW()), '-', MONTH(birthday), '-', DAY(birthday)) AS DATE)  
    BETWEEN NOW() AND NOW() + INTERVAL 30 DAY

Was mir hier nicht gefällt ist, dass  eine virtuelle Spalte „BirthdayInCurrentYear“ angelegt wird aber dann nicht mit dierser Spalte gearbeitet wird, sondern die Berechnung für die Spaltenwerte ein 2. Mal im Query steht.

Ich habe deshalb versucht, ob nicht irgendetwas mit [...] WHERE BirthdayInCurrentYear […] möglich ist. Aber es kommt dann immer zu einer Fehlermeldung, dass es so eine Spalte nicht gibt. So bin ich dann auf jetzt nicht mehr nachvollziehbaren Umwegen darauf gekommen, dass eine Weiterverarbeitung zwar nicht mit WHERE funktioniert, aber mit HAVING. (Etwas, das ich bis dato nicht mal gekannt habe.)

Und somit komme ich, nachdem ich mich den ganzen Tag damit beschäftigt habe, auf folgende Lösung:

SELECT m.id, m.name, m.familienname, m.geburtsdatum,  
CAST(CONCAT(YEAR(NOW()), '-', MONTH(m.geburtsdatum), '-', DAY(m.geburtsdatum)) AS DATE) AS BirthdayInCurrentYear,  
DATEDIFF(CAST(CONCAT(YEAR(NOW()), '-', MONTH(m.geburtsdatum), '-', DAY(m.geburtsdatum)) AS DATE),NOW()) AS differenz  
FROM mitglieder AS m  
HAVING BirthdayInCurrentYear BETWEEN NOW() - INTERVAL 4 DAY AND NOW() + INTERVAL 3 DAY  
ORDER BY BirthdayInCurrentYear ASC

Es werden, wie gewünscht, alle Personen aufgelistet, die ihren Geburtstag innerhalb der Zeitspanne heute - 3 Tage und heute + 3 Tage haben. Zusätzlich liedert der Query die virtuelle Spalte "differenz", in der die Tage seit bzw. bis zum Geburtstag stehen bzw. eine 0, wenn die Person heute Geburtstag hat.

Ewig gedauert hat es, bis ich drauf gekommen bin, dass es für die Geburtstage der vergangenen 3 Tage nötig ist, NOW() - INTERVAL 4 DAY zu schreiben. Zuerst fehlten nämlich immer die Personen mit Geburtstag vor genau 3 Tagen. Meine Versuche haben dann gezeigt, dass NOW() - INTERVAL x DAY alle Personen mit Geburtstagen in den letzten x-1 Tagen ausgibt.

Wie gesagt, ich habe ein funktionierendes Ergebnis. Und was ich noch habe, sind jetzt mehrere Fragen, weil ich so manches nicht nachvollziehen kann:

1.) Wieso kann ich eine virtuell erstellte Spalte nicht mit WHERE weiterverarbeiten, mit HAVING aber schon?

2.) Wieso greift NOW() + INTERVAL 3 DAY für die kommenden 3 Tage, aber NOW() - INTERVAL 3 DAY nur für die letzten 2 Tage?

3.) Bevor ich die Lösung mit dem BETWEEN hatte, habe ich auch in die Richtung ([…] > NOW() - INTERVAL 3 DAY ) AND ([…] < NOW() + INTERVAL 3 DAY ) herumexperimentiert. Da gab es aber nur Fehlermeldungen und nie ein Ergebnis. _Gäbe_ es denn einen Weg in die Richtung „größer als heute – 3 und kleiner als heute + 3“? (Abgesehen davon, dass die Lösung mit BETWEEN eh kürzer ist.)

4.) Was haltet Ihr generell von meiner Lösung? Ist das OK so oder völlig unbrauchbar? Ist das erste verlinkte Beispiel besser und wenn ja, warum?

5.) Und meine letzte Frage: Auch wenn meine Lösung funktioniert, würde ich trotzdem gerne den […]AS days\_to\_birthday Block der zuerst gefundenen Lösung verstehen. Kann mir das vielleicht wer ausdeutschen, was in diesem Teil der Query geschieht? Unter anderem verstehe ich die Stelle mit dem „ , 1, 0))“ nicht.

Ich möchte mich jetzt schon bedanken, falls sich wer dieser Sache annimmt und mir ein Feedback gibt!

Mit lieben Grüßen

Melvin Cowznofski

--

Melvin Cowznofski
What – me worry?