2010-02-08 6 views
5

Ich versuche, eine Ergebnismenge zu sortieren, die die 5 nächsten Benutzer sortiert nach bevorstehenden Geburtstag gibt. Dies funktioniert perfekt, bis Schaltjahre ins Spiel kommen. Zum Beispiel:mysql Geburtstagserinnerung, Schaltjahr

  • 15. Mai - 96 Tage nach links
  • 15. Mai - 97 Tage
  • links

Das Top-Ergebnis ist eine Geburt im Jahr 1987 und der unteren aus ist 1988 u_birth wird gespeichert als JJJJ-MM-TT. Gibt es eine einfache Möglichkeit, dieses Problem zu sortieren, ohne die gesamte Abfrage neu schreiben zu müssen?

SELECT u_birth, IF(DAYOFYEAR(u_birth) >= DAYOFYEAR(NOW()), 
      DAYOFYEAR(u_birth) - DAYOFYEAR(NOW()), 
      DAYOFYEAR(u_birth) - DAYOFYEAR(NOW()) + 
     DAYOFYEAR(CONCAT(YEAR(NOW()), '-12-31')) 
) 
AS distance 
FROM (blog_users) 
WHERE `s_agehide` = 0 
ORDER BY distance ASC 
LIMIT 5 

Diese Abfrage genommen wird und aus dem MySQL-Handbuch geändert: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#c7489

Antwort

7

Es gibt offensichtlich ein Problem, wenn Ihr Algorithmus vom Geburtsjahr der Person abhängt. Um dies zu umgehen, suchen Sie zuerst nach dem aktuellen Datum den nächsten Geburtstag jeder Person und berechnen Sie den Unterschied zwischen diesem Datum und jetzt.

SELECT u_birth, DATEDIFF(next_birthday, NOW()) AS distance FROM (
    SELECT *, ADDDATE(birthday, INTERVAL birthday < DATE(NOW()) YEAR) AS next_birthday 
    FROM (
     SELECT *, ADDDATE(u_birth, INTERVAL YEAR(NOW()) - YEAR(u_birth) YEAR) AS birthday 
     FROM blog_users 
     WHERE s_agehide = 0 
    ) AS T1 
) AS T2 
ORDER BY distance ASC 
LIMIT 5 

Ergebnisse:

'1992-02-29', 20 
'1993-03-01', 21 
'1987-05-15', 96 
'1988-05-15', 96 
'1988-09-18', 222 

Testdaten:

CREATE TABLE blog_users (u_birth NVARCHAR(100) NOT NULL, s_agehide INT NOT NULL); 
INSERT INTO blog_users (u_birth, s_agehide) VALUES 
('1987-05-15', 0), 
('1988-05-15', 0), 
('1988-09-20', 0), 
('2000-01-02', 0), 
('2000-01-03', 1), 
('1988-09-19', 0), 
('1988-09-18', 0), 
('1992-02-29', 0), 
('1993-03-01', 0); 

Beachten Sie, dass jemand an einem Schalttag geboren ist ein Geburtstag 28. Februar auf einem Nicht-Schaltjahr haben angenommen.

Außerdem enthält Ihre Abfrage nicht die Benutzer-ID des Benutzers. Wahrscheinlich möchtest du das auch hinzufügen, würde ich mir vorstellen.

+0

Danke! Ich sehe nach, gib mir ein paar Minuten, um es auszuprobieren =) – moodh

+0

@tired: Beachten Sie, dass ich eine kleine Änderung vorgenommen habe, so dass alle Menschen, deren Geburtstage heute sind, Abstand 0, nicht Entfernung 365 haben 'NOW()' zu 'DATE (NOW())'. –

+0

Es funktioniert wie es soll, aber ich habe eine Folge Frage: Wie kann ich zusätzliche Zeilen aus der Tabelle abrufen? Ich habe versucht in allen drei Auswahlen aber kein Glück, sagen wir, ich möchte auch s_agehide abrufen. Danke für die Hilfe! – moodh

1

nicht dayofyear als etwas nach 29. Februar in einem Schaltjahr ist ein Tag weiter als üblich anwenden. Extrahieren Sie stattdessen den Monat und den Tag und versehen Sie sie mit dem heutigen Jahr. Dann mach den Vergleich.

Wie so:

SELECT u_birth, 
    IF(DATE(CONCAT(YEAR(NOW()),'-',MONTH(u_birth),'-',DAY(u-birth))) >= DATE(NOW()), 
... 

ETA:

Genau so habe ich nicht den Ausdruck für die Umwandlung Geburtsdatum Geburtstag neu zu schreiben, werde ich es in einer Variablen bleiben. Ich empfehle Ihnen, eine Funktion zu schreiben, die die Konvertierung durchführt, damit Sie sie direkt in einer Abfrage verwenden können.

SET @birthday= SELECT DATE(CONCAT(YEAR(NOW()),'-',MONTH(u_birth),'-',DAY(u-birth))) FROM users WHERE user_id=x; //obviously only good for one value, but use the example for the calculation 

SELECT u_birth, 
     IF(DATE(@birthday)>=DATE(NOW()), 
      DATEDIFF(DATE_ADD(@birthday, INTERVAL 1 YEAR),NOW()), 
      DATEDIFF(NOW(),@birthday) 
     ) as days 
FROM users WHERE user_id=x; 
+0

Ich habe versucht, den ganzen Tag mit den Beispielen, die Sie gezeigt haben, zu ersetzen, ja, das Schaltjahr Problem verschwindet, aber der Wert und Sortierung ist komplett aus. Könnten Sie mir bitte die gesamte umgeschriebene Abfrage zeigen? – moodh

1

Vielleicht wird jemand von diesem Code-Frieden inspiriert.

Es perfekt in meinem Fall gearbeitet, aber ich denke, es gibt zu viel Datum-Berechnung ist ...

SELECT CONCAT(YEAR(CURRENT_DATE()),'-',DATE_FORMAT(FROM_UNIXTIME(date_of_birth), '%m-%d')), fe_users.* 
FROM `fe_users` 
WHERE `date_of_birth` != 0 AND (
    CONCAT(YEAR(CURRENT_DATE())+1,'-',DATE_FORMAT(FROM_UNIXTIME(date_of_birth), '%m-%d')) BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY) 
    OR 
    CONCAT(YEAR(CURRENT_DATE()),'-',DATE_FORMAT(FROM_UNIXTIME(date_of_birth), '%m-%d')) BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY) 
) 

Durch diesen Frieden von SQL-Code, den Sie alle Benutzer der Tabellen fe_users deren DATE_OF_BIRTH gespeichert bekommen (als Unix-Timestamp) wird innerhalb der nächsten 7 Tage sein. Sie können dies leicht auf 21 Tage verlängern, indem Sie das von der Funktion date_add() verwendete Intervall ändern.

+0

Übrigens - dieses Skript ist das beste im Falle der Leistung - wie ich getestet habe ... – SimonSimCity

2
SELECT 
    CONCAT(
     YEAR(CURRENT_DATE()), 
     '-', 
     DATE_FORMAT((birthDate), 
      '%m-%d' 
     ) 
    ), 
    fullName 
FROM 
    employees 
WHERE 
    birthDate != 0 
AND(
    CONCAT(
     YEAR(CURRENT_DATE())+ 1, 
     '-', 
     DATE_FORMAT((birthDate), 
      '%m-%d' 
     ) 
    )BETWEEN CURRENT_DATE() 
    AND DATE_ADD(
     CURRENT_DATE(), 
     INTERVAL 21 DAY 
    ) 
    OR CONCAT(
     YEAR(CURRENT_DATE()), 
     '-', 
     DATE_FORMAT((birthDate), 
      '%m-%d' 
     ) 
    )BETWEEN CURRENT_DATE() 
    AND DATE_ADD(
     CURRENT_DATE(), 
     INTERVAL 21 DAY 
    ) 
) 

ps: birth ist die Spalte, wo ich das Geburtsdatum der Mitarbeiter gespeichert. Mitarbeiter ist der Tabellenname.

Verwandte Themen