Consulta de MySQL para orderar los próximos cumpleaños según la date actual

Tengo la siguiente tabla de personas y sus cumpleaños:

name birthday ---------------------- yannis 1979-06-29 natalia 1980-08-19 kostas 1983-10-27 christos 1979-07-22 kosmas 1978-04-28 

y no tengo ni idea de cómo orderar los nombres de cuán cerca está el cumpleaños de hoy. Entonces, para NOW () = 2011-09-08, el resultado orderado debería ser:

 kostas 1983-10-27 kosmas 1978-04-28 yannis 1979-06-29 christos 1979-07-22 natalia 1980-08-19 

Estoy buscando un hack rápido, realmente no me importa el performance (el proyecto de mascota – table tendrá less de 1000 loggings), pero por supuesto, cada sugerencia será muy apreciada.

Aquí hay una manera:

  • Calcular año actualaño de nacimiento
  • Agregue el número de años resultante a la date de nacimiento
  • Ahora tienes el cumpleaños de este año, si esta date ha pasado, agrega un año más
  • Ordenar los resultados por esa date
 SELECT name, birthday, birthday + INTERVAL(YEAR(CURRENT_TIMESTAMP) - YEAR(birthday)) + 0 YEAR AS currbirthday, birthday + INTERVAL(YEAR(CURRENT_TIMESTAMP) - YEAR(birthday)) + 1 YEAR AS nextbirthday FROM bd ORDER BY CASE WHEN currbirthday >= CURRENT_TIMESTAMP THEN currbirthday ELSE nextbirthday END 

SQLFiddle

Parece ser bastante rápido, no hay problemas con los años bisiestos:

 SELECT * FROM `people` ORDER BY CONCAT(SUBSTR(`birthday`,6) < SUBSTR(CURDATE(),6), SUBSTR(`birthday`,6)) 

Все гениальное – просто! 😉

 SELECT name , birthday FROM TableX ORDER BY DAYOFYEAR(birthday) < DAYOFYEAR(CURDATE()) , DAYOFYEAR(birthday) 

No, lo anterior puede producir resultados de error, debido a los años con 366 días. Esto es correcto:

 SELECT name , birthday FROM ( SELECT name , birthday , MONTH(birthday) AS m , DAY(birthday) As d FROM TableX ) AS tmp ORDER BY (m,d) < ( MONTH(CURDATE()), DAY(CURDATE()) ) , m , d 

Si su tabla crece a más de unos pocos miles de loggings, será muy lenta. Si desea una consulta rápida, agregue campos con el mes y el día y tenga un índice el (bmonth,bday) o agréguelos como un solo campo, ya sea Char ( 08-17 o 0817 para el 17 de agosto) o Int ( 817 para el 17 -Aug) y un índice en ese campo.

No es bonito, pero funciona

 SELECT * ,CASE WHEN BirthdayThisYear>=NOW() THEN BirthdayThisYear ELSE BirthdayThisYear + INTERVAL 1 YEAR END AS NextBirthday FROM ( SELECT * ,birthday - INTERVAL YEAR(birthday) YEAR + INTERVAL YEAR(NOW()) YEAR AS BirthdayThisYear FROM bd ) AS bdv ORDER BY NextBirthday 

Lo probaría así (pero esto no está probado):

 SELECT name, birthday FROM birthdays ORDER BY ABS( DAYOFYEAR(birthday) - (DAYOFYEAR(CURDATE()) ) ASC 

EDITAR:
cambió el order de DESC a ASC porque desea get el más lejano primero, no el más cercano.