Сортировать предстоящие дни рождения по текущей дате - PullRequest
5 голосов
/ 08 сентября 2011

У меня есть следующая таблица людей и их дней рождения:

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

, и я не знаю, как отсортировать имена по тому, как ближе день рождения к сегодняшнему дню.Таким образом, для NOW () = 2011-09-08 отсортированный результат должен быть следующим:

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

Я ищу быстрый взлом, на самом деле не заботюсь о производительности (домашний проект - таблица будет держать меньшечем 1000 записей), но, конечно, каждое предложение будет чрезвычайно оценено.

Ответы [ 5 ]

11 голосов
/ 08 сентября 2011

Вот один из способов:

  • Рассчитать текущий год - год рождения
  • Добавьте полученное количество лет к дате рождения
  • У вас есть день рождения в этом году, если эта дата прошла, добавьте еще один год
  • Сортировать результаты по этой дате
SELECT
    name,
    birthday,
    birthday + INTERVAL (YEAR(CURRENT_DATE) - YEAR(birthday))     YEAR AS currbirthday,
    birthday + INTERVAL (YEAR(CURRENT_DATE) - YEAR(birthday)) + 1 YEAR AS nextbirthday
FROM birthdays
ORDER BY CASE
    WHEN currbirthday >= CURRENT_DATE THEN currbirthday
    ELSE nextbirthday
END

Примечания:

  • Сегодняшние дни рождения появляются первыми независимо от текущего времени.
  • День рождения 29 февраля считается равным дню рождения 28 февраля в обычные годы, например
    • 1 января 2019 г. и 28 февраля, и 29 февраля (2019 г.) сортируются равными
    • В период с 1 марта 2019 г. по 28 февраля и 29 февраля (2020 г.) отсортировано в соответствии с ожиданиями

SQLFiddle

5 голосов
/ 08 сентября 2011
SELECT name
     , birthday
FROM TableX
ORDER BY DAYOFYEAR(birthday) < DAYOFYEAR(CURDATE())
       , DAYOFYEAR(birthday)

Нет, приведенные выше данные могут привести к ошибкам из-за лет с 366 днями.Это правильно:

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

Если ваша таблица увеличится до нескольких тысяч записей, это будет очень медленно.Если вам нужен быстрый запрос, добавьте поля с месяцем и днем ​​и индексом на (bmonth,bday) или добавьте их как одно поле: Char (08-17 или 0817 для 17 августа) или Int (81717 августа) и указатель на это поле.

4 голосов
/ 29 марта 2012

Кажется, довольно быстро, никаких проблем с високосными годами:

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

Все гениальное - просто!;)

2 голосов
/ 08 сентября 2011

Не красиво, но работает

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
0 голосов
/ 08 сентября 2011

я бы попробовал вот так (но это не проверено):

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

EDIT:
изменен порядок с DESC на ASC, потому что вы хотите получить самое дальнее, а не самое близкое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...