以自然顺序提取生日

时间:2009-09-16 15:44:41

标签: sql mysql

给出下面的mysql表:

ID|name|year|month|day
----------------------
1 |john|1978|5|1  
2 |mike|1979|7|23  
3 |bob |1985|2|14  
4 |joe |1964|2|16  
5 |jane|1975|9|22

我正在尝试按照他们的生日事件,即将到来的生日顺序提取用户。 因此,如果查询在9月16日执行,则顺序应为:jane,bob,joe,john,mike。

7 个答案:

答案 0 :(得分:8)

SELECT  u.*, CAST(CONCAT_WS('.', YEAR(SYSDATE()) + (CAST(CONCAT_WS('.', YEAR(SYSDATE()), month, day) AS DATE) < SYSDATE()), month, day) AS DATE) AS nbd
FROM    t_users u
ORDER BY
        nbd;

ORDER BY表达式采用当前年份的生日与当前日期的比较的布尔结果,并将其添加到当前年份。

这导致下一个生日(表示为DATE),可以在其上订购该声明。

作为奖励,您可以轻松获得下一个生日:

5, 'jane',  1975, 9, 22, '2009-09-22'
3, 'bob',   1985, 2, 14, '2010-02-14'
4, 'joe',   1964, 2, 16, '2010-02-16'
1, 'john',  1978, 5, 1,  '2010-05-01'
2, 'mike',  1979, 7, 23, '2010-07-23'

<强>更新

此查询可以更好地处理闰年。

SELECT  u.*, CAST(CONCAT_WS('.', year, month, day) AS DATE),
        CAST(CONCAT_WS('.', 1980, month, day) AS DATE) + INTERVAL YEAR(SYSDATE()) - 1980 YEAR +
        INTERVAL CAST(CONCAT_WS('.', 1980, month, day) AS DATE) + INTERVAL YEAR(SYSDATE()) - 1980 YEAR < SYSDATE() YEAR AS nbd
FROM    t_users u
ORDER BY
        nbd;

它假设Feb 29出生的人的非闰年生日为Feb 28

我添加了一个名为Alex的人,他出生于Feb 29, 1980

5, 'jane', 1975, 9, 22, '1975-09-22', '2009-09-22'
3, 'bob',  1985, 2, 14, '1985-02-14', '2010-02-14'
4, 'joe',  1964, 2, 16, '1964-02-16', '2010-02-16'
6, 'alex', 1980, 2, 29, '1980-02-29', '2010-02-28'
1, 'john', 1978, 5, 1,  '1978-05-01', '2010-05-01'
2, 'mike', 1979, 7, 23, '1979-07-23', '2010-07-23'

答案 1 :(得分:2)

如果您将生日存储为日期对象,则可以使用:

SELECT * 
FROM BirthdayTable
ORDER BY dayofyear(birthdayDateColumn - INTERVAL dayofyear(now()) -1 DAY)

或者,将日期字段分开,我认为您可以使用以下内容:

SELECT * 
FROM BirthdayTable
ORDER BY dayofyear(cast(CONCAT_WS("-", year, month, day) as date) - INTERVAL dayofyear(now()) -1 DAY)

这些ORDER BY语句根据当年的生日(一年中的当天)对生日进行排序,以便从每个生日的今天开始订购。

答案 2 :(得分:1)

我本可以将出生日期存储在日期格式中,但请注意,尝试做这样的事情 - 选择所有出生日期转换为下一个生日日期的人,然后对此进行排序。使用STR_TO_DATE在MySQL中使用任意字符串创建日期很容易。然后,您只需要执行IF语句来选择正确的年份。尝试这样的事情:

SELECT * FROM (
    SELECT name, IF(
        STR_TO_DATE(CONCAT(YEAR(NOW()), '-', month, '-', day)) < NOW(),
        STR_TO_DATE(CONCAT(YEAR(NOW())+1, '-', month, '-', day)), 
        STR_TO_DATE(CONCAT(YEAR(NOW()), '-', month, '-', day))) AS next_birthday 
    FROM people) as next_birthdays 
 ORDER BY next_birthday;

我认为应该这样做。当然,如果您有一个DATE类型的生日列,那会更容易。

答案 3 :(得分:1)

最优雅的解决方案是完全忽略年限。无需将任何内容转换为日期类型即可执行排序。

相反,创建一个排序键,假设所有月份都是31天(最大值)。当月份未来时,添加月* 31天。在过去,加上一年加。然后为当天添加偏移量。

对于当月,请查看当月的日期,并执行相同的操作:如果将来添加它。如果没有,请加上12“长”(31天)的月份。

此解决方案可在闰年中正常运行,无需将各个字段转换为日期。

 SELECT * FROM mytable ORDER BY
     CASE 
       /* Month has passed this year, sort key considers it a "long year" further in the future) */
       WHEN month - MONTH(NOW()) < 0 THEN (month+12) * 31 + day
       /* Month has not passed year, sort key is a "long month" + days in the future */
       WHEN month - MONTH(NOW()) > 0 THEN month * 31 + day
       /* Same month, so we have to compare based on the day of the month */
       ELSE
         CASE 
           WHEN day - DAY(NOW()) < 0 THEN day + (12*31)
           ELSE day
       END CASE
     END CASE

答案 4 :(得分:0)

SELECT *
  FROM table
 ORDER BY CASE WHEN month*100+day > MONTH(getdate())*100+DAY(getdate())
           THEN (month - MONTH(getdate()))*100 + day - DAY(getdate())
           ELSE (12 + month - MONTH(getdate()))*100 + day - DAY(getdate())
      END

答案 5 :(得分:0)

这是一种方式

select *
from foo 
order by 
if ( (dayofyear(concat(year(now()),'-',month,'-',day))-dayofyear(now())) < 0,
     (dayofyear(concat(year(now()),'-',month,'-',day))-dayofyear(now()))+365,
     (dayofyear(concat(year(now()),'-',month,'-',day))-dayofyear(now()))
   );

基本上,它按照直到今年生日的天数排序,除非是过去的情况,在这种情况下,它会再添加365天来查看它到底有多少天。

答案 6 :(得分:-2)

所以索引只涉及一个字段

ID|name|year|month|day|orderextrac
----------------------
1 |john|1978|5|1  |19780501
2 |mike|1979|7|23 |19790723 
3 |bob |1985|2|14 |19850214
4 |joe |1964|2|16 |19640216
5 |jane|1975|9|22 |19750922

select name from table1 order orderextrac