Geburtstag und -monat aus MySQL auslesen
Ben
- datenbank
2 suit0 Deus Figendi0 Deus Figendi0 ChrisB0 Vinzenz Mai
0 Tom0 Tom
Hallo liebe Forenmitglieder,
für eine Adressliste möchte ich die Einträge aller Personen auslesen, die in den nächsten sieben Tagen Geburtstag haben.
Die Geburtstage sind als DATE abgespeichert und daher erfolgt das Auslesen derzeit nach folgendem Schema:
SELECT * FROM nutzer WHERE (RIGHT(geb,5) >= RIGHT(CURDATE(),5)) AND (RIGHT(geb,5) < RIGHT(DATE_ADD(CURDATE(), INTERVAL 7 DAY),5));
Leider scheitert diese Methode jedoch an den Jahreswechseln, weshalb ich dies gerne anderweitig lösen würde. Auch die Abfrage über BETWEEN ist für normale Datumsangaben prinzipiell recht einfach, doch wie setze ich es um wenn jede Zeile ein anderes Jahr enthält?
Besten Dank im Voraus,
Ben
doch wie setze ich es um wenn jede Zeile ein anderes Jahr enthält?
Du könntest z.B. nur DAYOFYEAR() vergleichen - damit hast du nur am Jahreswechsel 7 Tage lang ein Problem mit dieser Methode - das könntest du damit kompensieren, indem du die zu berechendende Tagesspanne mit einbeziehst und dazurechnest.
Ich habe nur mäßige Erfahrung mit Datums-Werten, aber in der MySQL-Doku steht wörtlich:
Es folgt ein Beispiel, welches Datumsfunktionen verwendet. Die folgende
Abfrage wählt alle Datensätze aus, die einen date_col-Wert haben, der
in den letzten 30 Tagen liegt:
SELECT something FROM tbl_name
WHERE DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= date_col;
Scheint mir genau das zu sein, was du suchst.
Ansonsten wäre mein Ansatz UNIX_TIMESTAMP()
WHERE (UNIX_TIMESTAMP(geb) = UNIX_TIMESTAMP(now()));
Oder so
WHERE (UNIX_TIMESTAMP(geb) = UNIX_TIMESTAMP(now()));
Oder so
Quatsch "gleich" dann natürlich mit BETWEEN now() und now()+7*24*60*60
Hi,
Ich habe nur mäßige Erfahrung mit Datums-Werten, aber in der MySQL-Doku steht wörtlich:
Es folgt ein Beispiel, welches Datumsfunktionen verwendet. Die folgende
Abfrage wählt alle Datensätze aus, die einen date_col-Wert haben, der
in den letzten 30 Tagen liegt
Mein Geburtsdatum liegt aber nicht innerhalb der letzten 30 Tage - andernfalls wäre ich vermutlich eher nicht in der Lage, dir hier zu Antworten. (Und wenn doch, dann wäre es vermutlich eher sowas wie "hihi glucks gagga, ra-bäähäh!")
MfG ChrisB
Mein Geburtsdatum liegt aber nicht innerhalb der letzten 30 Tage - andernfalls wäre ich vermutlich eher nicht in der Lage, dir hier zu Antworten. (Und wenn doch, dann wäre es vermutlich eher sowas wie "hihi glucks gagga, ra-bäähäh!")
Ääh fürwahr, ich sollte sieben Sekunden länger denken bevor ich antworte.
Hallo,
Ansonsten wäre mein Ansatz UNIX_TIMESTAMP()
WHERE (UNIX_TIMESTAMP(geb) = UNIX_TIMESTAMP(now()));
Oder so
UNIX_TIMESTAMP() ist für viele relevanten Geburtsdaten, zum Beispiel mein eigenes, ungeeignet. Ich rate von der Verwendung von Timestamps für solche Datumsangaben dringendst ab. Wozu gibt es ordentliche Datumsdatentypen?
Freundliche Grüße
Vinzenz
Hello,
Leider scheitert diese Methode jedoch an den Jahreswechseln, weshalb ich dies gerne anderweitig lösen würde. Auch die Abfrage über BETWEEN ist für normale Datumsangaben prinzipiell recht einfach, doch wie setze ich es um wenn jede Zeile ein anderes Jahr enthält?
Du kannst das Vergleichsdatum doch zusammensetzen aus
aktuelles Jahr, Monat des Geburtstages, Tag des Geburtstages
Und das kannst Du dann in Deine Between-Bedingung einsetzen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
Du kannst das Vergleichsdatum doch zusammensetzen aus
aktuelles Jahr, Monat des Geburtstages, Tag des Geburtstages
Und das kannst Du dann in Deine Between-Bedingung einsetzen.
select * from zeit
where datediff
(
date_add(now(), interval 7 day),
concat(year(now()),'-',month(birthday),'-',day(birthday))
)
between 0 and 7;
so geht es.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hallo Tom,
select * from zeit
where datediff
(
date_add(now(), interval 7 day),
concat(year(now()),'-',month(birthday),'-',day(birthday))
)
between 0 and 7;
> so geht es.
nein, so geht es nicht immer. [suit](https://forum.selfhtml.org/?t=186764&m=1240651) hatte bereits auf den Jahreswechsel hingewiesen, den Dein Code nicht berücksichtigt. suit vergaß allerdings auf die Schaltjahrproblematik hinzuweisen, die bei der Verwendung von DAYOFYEAR zusätzlich berücksichtigt werden muss.
Dein Code vernachlässigt die Schaltjahresproblematik in der Form, dass Personen nicht am 29. Februar geboren sein dürfen :-)
~~~sql
SELECT
DATEDIFF(
DATE_ADD(NOW(), INTERVAL 7 DAY),
'2009-02-28'
) differenz
liefert mir 82 als Wert,
SELECT
DATEDIFF(
DATE_ADD(NOW(), INTERVAL 7 DAY),
'2009-02-29'
) differenz
jedoch NULL.
Freundliche Grüße
Vinzenz
Hello Vinzenz,
select * from zeit
where datediff
(
date_add(now(), interval 7 day),
concat(year(now()),'-',month(birthday),'-',day(birthday))
)
between 0 and 7;
> > so geht es.
>
> nein, so geht es nicht immer. [suit](https://forum.selfhtml.org/?t=186764&m=1240651) hatte bereits auf den Jahreswechsel hingewiesen, den Dein Code nicht berücksichtigt. suit vergaß allerdings auf die Schaltjahrproblematik hinzuweisen, die bei der Verwendung von DAYOFYEAR zusätzlich berücksichtigt werden muss.
Stimmt. Ertappt. Dabei habe ich wohl im Kreis gedacht.
Aber der betrachtete Bereich verlässt ja den gültigen für year(now())...
Ok, das könnte man einfach fixen, indem man das nächste Jahr auch abfragt. Da sich diese beiden Bereiche nicht überschneiden, dürfte es passen.
Und für den 29. Februar, der mMn nach als amtlicher Geburtstag nicht angegeben wird, müsste wohl ein if() her?
~~~sql
select * from zeit
where datediff
(
date_add(now(), interval 7 day),
concat(year(now()),'-',month(birthday),'-',if(month(birthday) = 2 and day(birthday)= 29,28,day(birthday))
)
between 0 and 7
or datediff
(
date_add(now(), interval 7 day),
concat((year(now())+1),'-',month(birthday),'-',if(month(birthday) = 2 and day(birthday)= 29,28,day(birthday))
)
between 0 and 7
;
Dein Code vernachlässigt die Schaltjahresproblematik in der Form, dass Personen nicht am 29. Februar geboren sein dürfen :-)
der 29.02.2009 lässt sich gar nicht eintragen in die DB
mysql> insert into zeit set name="Vierauge", birthday='2009-02-29';
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select * from zeit;
+----+------------+------------+
| id | name | birthday |
+----+------------+------------+
| 1 | NULL | 1958-02-08 |
| 2 | Margret | 1933-01-07 |
| 3 | Wolfgang | 1930-08-25 |
| 4 | Elke | 1964-12-03 |
| 5 | Louisa | 1984-01-15 |
| 6 | Thomas | 1958-02-08 |
| 7 | Paul | 1960-05-20 |
| 8 | Paula | 1970-05-21 |
| 9 | Paulinchen | 1970-05-12 |
| 10 | Vierauge | 0000-00-00 |
+----+------------+------------+
10 rows in set (0.00 sec)
während sich für ein Jahr, in dem es einen 29. Februar gibt, dieser auch angenommen wird. MySQL ist also auch hier inzwischen etwas schlauer geworden.
mysql> insert into zeit set name="Willi-2008", birthday='2008-02-29';
Query OK, 1 row affected (0.00 sec)
mysql> select * from zeit;
+----+------------+------------+
| id | name | birthday |
+----+------------+------------+
| 1 | NULL | 1958-02-08 |
| 2 | Margret | 1933-01-07 |
| 3 | Wolfgang | 1930-08-25 |
| 4 | Elke | 1964-12-03 |
| 5 | Louisa | 1984-01-15 |
| 6 | Thomas | 1958-02-08 |
| 7 | Paul | 1960-05-20 |
| 8 | Paula | 1970-05-21 |
| 9 | Paulinchen | 1970-05-12 |
| 10 | Vierauge | 0000-00-00 |
| 11 | Willi-2008 | 2008-02-29 |
+----+------------+------------+
11 rows in set (0.00 sec)
Der Code sollte jetzt nur eine Anregung sein, für den Fall, dass man den 29.02.2009 tatsächlich berücksichtigen müsste. Da diese Datum aber bei MySQL 5.0.51a (bei mir hier noch verwendet) gar nicht mehr eingetragen werden kann, sollte es also ohne zusätzliche Bedingungen gehen.
Vermutlich müsste der Code er für eine "amtliche" Geburtstagswoche sowieso noch komplizierter werden, weil die Geburtstagslinder in DE vom 29. Februar auf den ersten März verfrachtet werden.
Man müsste also auch erst noch etwas über die lokalen Gesetzmässigleiten wissen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hallo Tom,
Und für den 29. Februar, der mMn nach als amtlicher Geburtstag nicht angegeben wird, müsste wohl ein if() her?
selbstverständlich steht bei Personen, die am 29. Februar eines Schaltjahres geboren werden, das korrekte Geburtsdatum, der 29. Februar im Ausweis und allen Papieren. Warum sollten dort Angaben verfälscht werden?
Freundliche Grüße
Vinzenz
Hallo Tom,
select * from zeit
where datediff
(
date_add(now(), interval 7 day),
concat(year(now()),'-',month(birthday),'-',if(month(birthday) = 2 and day(birthday)= 29,28,day(birthday))
)
between 0 and 7or datediff
(
date_add(now(), interval 7 day),
concat((year(now())+1),'-',month(birthday),'-',if(month(birthday) = 2 and day(birthday)= 29,28,day(birthday))
)
between 0 and 7
;
nein, das berücksichtigt den Schalttag immer noch nicht korrekt:
Am 21. Februar eines Schaltjahres behauptet Dein Statement, eine am 29. Februar eines anderen Schaltjahres geborene Person habe innerhalb der nächsten 7 Tage Geburtstag.
Freundliche Grüße
Vinzenz
Hello,
stimmt sowieso immer noch nicht.
Die Korrektur der letzten Tage (hier 7) muss ja auf jeden Fall stattfinden...
Nun suche ich aber erstmal, warum ich diese Fehlermeldung bekomme.
Die war ja vorhin nicht da.
ERROR 1305 (42000): FUNCTION test.datediff does not exist
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello Vinzenz,
nun dachte ich, so müsste es funktionieren, aber nun bekomme ich die Fehlermeldung
ERROR 1305 (42000): FUNCTION test.datediff does not exist
[code lang=sql]
select * from zeit
where datediff
(
date_add(now(), interval 7 day),
if(
month(birthday) = 2 and day(birthday)= 29 and DAYOFYEAR(CONCAT(YEAR(NOW()),'-12-31')) = 365,
concat(YEAR(NOW()),'-03-01'),
if(
month(now()) = 12 and day(now()) > (31-7),
concat((YEAR(NOW())+1),'-',month(birthday),'-',day(birthday)),
concat(YEAR(NOW()),'-',month(birthday),'-',day(birthday))
)
)
)
between 0 and 7
;
Was habe ich denn nun übersehen?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
Ok, letzter Anlauf.
Der Fehler rührte daher, weil MySQL keine Leerzeichen (oder Whitespaces) zwischen dem Funktionsnamen und der öffnenden Klammer duldet.
Die Abfrage müsste mMn nun aber so benutztbar sein, wenn sie auch recht unhandlich geworden ist. Ich würde auf jeden Fall eine benutzerdefinierte Funktion daraus machen.
select * from zeit
where datediff(
date_add(now(), interval 7 day),
if(
month(birthday) = 2 and day(birthday)= 29 and DAYOFYEAR(CONCAT(YEAR(NOW()),'-12-31')) = 365,
concat(YEAR(NOW()),'-03-01'),
if(
month(now()) = 12 and day(now()) > (31-7),
concat((YEAR(NOW())+1),'-',month(birthday),'-',day(birthday)),
concat(YEAR(NOW()),'-',month(birthday),'-',day(birthday))
)
)
)
between 0 and 7
;
Wenn der Geburtstag auf einen 29. Februar fällt und das Jahr kein Schaltjahr ist, muss der Geburtstag korrigiert werden auf den (in DE) 01.03.
Da er aber nun auf den 01.03. fällt, muss nicht geprüft werden, ob er in die letzte Woche des Jahres fällt (da war meine boolesche Algebra also doch nicht für den A....). Wenn es sich aber um ein gültiges Datum handelt (also auch ein 29. Februar in einem Schaltjahr) regelt MySQL alles, bis auf die letzte Woche. Die muss nun noch kontrolliert werden. Der Stichtag dann ins nächste Jahr verschoben.
Jetzt muss nur noch überlegt werden, ob 8 (0 bis 7) oder 7 Tage betrachtet werden sollen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg