2010-02-08 83 views
5

我試圖理清一個結果集,它給出了按照即將到來的生日排序的5個最接近的用戶。在閏年發揮作用之前,這完美運作。例如:mysql生日提醒,閏年

  • 5月15日 - 97天了
  • 5月15日 - 98天了

頂部結果是在1987年出生和下從1988年 u_birth存儲爲YYYY-MM-DD。 有沒有簡單的方法來排序這個問題,而不必重寫整個查詢?

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 

此查詢取並修改從MySQL手冊:http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#c7489

回答

7

如果你的算法取決於人的出生年份,那麼顯然存在一個問題。要解決這個問題,首先在當前日期之後查找每個人的下一個生日,然後計算該日期與現在之間的差異。

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 

結果:

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

測試數據:

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); 

注意,有人出生在一個閏日被假定爲具有2月28日對非閏年生日。

另外,您的查詢不包括用戶的用戶標識。我想可能你也想補充一點。

+0

謝謝!我會看看,給我幾分鐘試一下=) – moodh 2010-02-08 20:14:45

+0

@tired:請注意,我做了一個小的改變,以便所有今天生日的人都有距離0,而不是距離365。 'NOW()'到'DATE(NOW())'。 – 2010-02-08 20:18:51

+0

它的工作原理是,但我有一個後續問題: 如何從表中檢索額外的行?我已經嘗試過所有三次選擇,但沒有運氣,可以說我也想檢索s_agehide。 感謝您的幫助! – moodh 2010-02-08 20:20:35

1

不要在閏年使用dayofyear作爲任何2月29日之後爲一天進一步上比平常。取而代之的是提取月份和日期,並將它們與今年的一起進行連接。然後做比較。

像這樣:

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

ETA:

只是讓我不必重寫表達式出生日期轉換爲生日,我會在一個變量堅持下去。我建議你編寫一個轉換函數,以便你可以直接在查詢中使用它。

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

我嘗試用您顯示的示例替換所有dayofyear,是的,閏年問題消失,但值和排序完全關閉。你能告訴我整個重寫的查詢嗎? – moodh 2010-02-08 20:13:00

1

也許有人從代碼的和平中受到啓發。

它完美地工作在我的情況,但我認爲有得多日期計算......

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) 
) 

通過這種和平的SQL代碼,你會得到表fe_users其DATE_OF_BIRTH的所有用戶(保存作爲unix-timestamp)將在未來7天內完成。通過更改date_add()函數使用的時間間隔,您可以輕鬆地將其延長至21天。

+0

順便說一句 - 這個腳本是最好的表現 - 我已經測試過... – SimonSimCity 2011-02-09 01:18:12

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:生日是我保存了員工的出生日期列。 員工是表名。