Нахождение MySql в течение n дней - PullRequest
7 голосов
/ 20 мая 2010

У меня есть таблица с юбилейными датами. Я хочу запрос, который возвращает мне ряды юбилеев в ближайшие 10 дней. Например:

birthdate
---------
1965-10-10
1982-05-25


SELECT birthdate FROM Anniversaries WHERE mystical_magical_mumbo_jumbo <= 10

+------------+
| birthdate  |
+------------+
| 1982-05-25 |
+------------+
1 row in set (0.01 sec)

Я хотел бы сохранить запрос в форме x <= 10, потому что я буду использовать это число 10 в других частях запроса, и если я задам его как переменную, я могу изменить его один раз везде, изменив переменная, и не нужно переписывать запрос.

Ответы [ 7 ]

7 голосов
/ 20 мая 2010

Как уже говорили другие, вам нужно игнорировать год в вашем сравнении. Функция DAYOFYEAR () - это один из способов сделать это.

Вот быстрое решение с моей головы. Он вернет все дни рождения в следующие 10 дней, даже если это конец декабря и день рождения в следующем году.

Он НЕ обрабатывает високосные годы должным образом, поэтому он будет отключен на 1 день для дней рождения в начале марта, если этот год является високосным, и человек не родился в високосный год или наоборот. Високосные годы также приводят к тому, что дни рождения в начале января иногда появляются на выходных в конце декабря. Если кто-то хочет добавить коррекцию високосного года, не стесняйтесь:)

SELECT birthdate 
FROM Anniversaries 
WHERE dayofyear(birthdate) - dayofyear(curdate()) between 0 and 10 
or dayofyear(birthdate) + 365 - dayofyear(curdate()) between 0 and 10;
1 голос
/ 23 января 2011

То, что мы хотим достичь, это список годовщин, происходящих в недавнем диапазоне дат. Чтобы достичь этого и выполнить перенос, нам нужно создать список всех годовщин, которые охватывают диапазон дат. Решение, которое я использовал, генерирует записи годовщины за прошлый год, этот год и следующий год и выводит только те записи, которые попадают в данный диапазон дат. Запрос объединения выглядит следующим образом:

SELECT Date_Add(birth_date,INTERVAL (Year(now())-Year(birth_date)-1) YEAR) as dt,  
FROM Anniversaries 
WHERE Date_Add(birth_date,INTERVAL (Year(now())-Year(Date)-1) YEAR) 
BETWEEN Date_sub(now(), INTERVAL 7 Day) AND Date_add(now(), INTERVAL 21 Day) 
UNION
SELECT Date_Add(birth_date,INTERVAL (Year(now())-Year(birth_date)) YEAR) as dt,
FROM Anniversaries 
WHERE Date_Add(birth_date,INTERVAL (Year(now())-Year(Date)) YEAR) 
BETWEEN Date_sub(now(), INTERVAL 7 Day) AND Date_add(now(), INTERVAL 21 Day) 
UNION
SELECT Date_Add(birth_date,INTERVAL (Year(now())-Year(birth_date)+1) YEAR) as dt,
FROM Anniversaries 
WHERE Date_Add(birth_date,INTERVAL (Year(now())-Year(Date)+1) YEAR) 
BETWEEN Date_sub(now(), INTERVAL 7 Day) AND Date_add(now(), INTERVAL 21 Day) 
ORDER BY dt

Первый оператор SELECT увеличивает все даты до прошлого года и выбирает любые элементы, попадающие в указанный диапазон дат. Следующая инструкция SELECT увеличивает все даты до текущего года и выбирает любые элементы, попадающие в указанный диапазон дат. Последний оператор SELECT увеличивает все даты на следующий год и выбирает любые элементы, попадающие в указанный диапазон дат. Наконец все упорядочено по дате.

Вот, пожалуйста. Это позволит надежно выбрать юбилеи в данный период. Если требуется более длительный период, может потребоваться сгенерировать дополнительные операторы SELECT и объединить их с UNION. Я изменил свой код в соответствии с приведенным выше примером, но не проверял его с момента модификации.

1 голос
/ 20 мая 2010

Попробуйте это

SELECT birthdate FROM Anniversaries 
WHERE DATEDIFF(CURTIME(),birthdate) >= 0 
AND DATEDIFF(CURTIME(),birthdate) <= 10 

Проверьте это для справки MySQL DATEDIFF

DATEDIFF (expr1, expr2)

DATEDIFF () возвращает expr1 - expr2, выраженное в виде значений в днях от одной даты до другой. expr1 и expr2 являются выражениями даты или даты и времени. При расчете используются только части даты значений.

mysql> SELECT DATEDIFF ('2007-12-31 23:59:59', '2007-12-30'); -> 1

mysql> SELECT DATEDIFF ('2010-11-30 23:59:59', '2010-12-31'); -> -31

0 голосов
/ 30 марта 2013
     SELECT firstName, lastName, DOB, if( (
     datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date ) ) >=0, (
    datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )), 
    datediff( date( concat( year( current_date ) +1, '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )
)DAYSTOBDAY
    FROM birthinfo
    WHERE (
    if( (
    datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date ) ) >=0, (
    datediff( date( concat( year( current_date ) , '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )),
    datediff( date( concat( year( current_date ) +1, '-', month( DOB ) , '-', day( DOB ) ) ) , current_date )
    )
    )
    BETWEEN 0
    AND 31

   firstName    lastName    DOB             DAYSTOBDAY
   Michelle     Smith       1979-04-16          17
   Kirsten      Dunst       1982-04-30          31

Это так далеко от того, чтобы быть «хорошим» ответом, это не смешно, но работает изо всех сил, что работает. добиться того, что вы хотите. Я создал таблицу с именами, фамилиями и DOB, вы можете просто заменить ее на все вокруг.

0 голосов
/ 20 мая 2010

MAKEDATE() создает дату из года и дня года, поэтому я могу использовать ее, чтобы вычеркнуть старые годы из картинки:

SELECT 
    anniversary
    ,  MAKEDATE( YEAR(NOW()), DAYOFYEAR(anniversary) ) AS thisyear 
FROM Anniversaries;

+-------------+-------------+
| anniversary | thisyear    | 
+-------------+-------------+
| 1978-07-29  | 2010-07-29  |
| 1959-04-17  | 2010-04-17  |
+-------------+-------------+

Тогда я могу использовать DATEDIFF() для вычисления дней до (или из) затем:

SELECT 
    anniversary
    , MAKEDATE( YEAR(NOW()), DAYOFYEAR(anniversary) ) AS thisyear
    , DATEDIFF( MAKEDATE(YEAR(NOW()),DAYOFYEAR(anniversary)), NOW()) as days 
FROM Anniversaries;

+-------------+-------------+------+
| anniversary | thisyear    | days | 
+-------------+-------------+------+
| 1978-07-29  | 2010-07-29  |   70 |
| 1959-04-17  | 2010-04-17  |  -33 |
+-------------+-------------+------+

Предполагается, что ТЕПЕРЬ () равно 5 / 20.


Редактировать , поэтому вышеупомянутое не работает при смене года. Одно решение состоит в том, чтобы добавить другой расчет, где юбилей - следующий год. Здесь я жестко закодировал дату '2010-12-31' и использовал OR в предложении HAVING для фильтрации по дням, которые совпадают в этом или следующем году:

SELECT birth_date
, MAKEDATE(YEAR('2010-12-31'),DAYOFYEAR(birth_date)) as anniversary
,  DATEDIFF( MAKEDATE(YEAR('2010-12-31'),DAYOFYEAR(birth_date)), '2010-12-31') as days
, MAKEDATE(YEAR(NOW())+ 1,DAYOFYEAR(birth_date)) as next_anniversary
, DATEDIFF( MAKEDATE(YEAR(NOW())+ 1,DAYOFYEAR(birth_date)), '2010-12-31') as next_days 
FROM Anniversaries 
HAVING ( ( days <= 25 AND days > 0 ) OR next_days <= 25 );

+------------+-------------+------+------------------+-----------+
| birth_date | anniversary | days | next_anniversary | next_days |
+------------+-------------+------+------------------+-----------+
| 2010-01-23 | 2010-01-23  | -342 | 2011-01-23       |        23 |
| 1975-01-11 | 2010-01-11  | -354 | 2011-01-11       |        11 |
+------------+-------------+------+------------------+-----------+
2 rows in set (0.00 sec)
0 голосов
/ 20 мая 2010

На основании ответа Алехандробога:

SELECT birthdate FROM Anniversaries
WHERE DATEDIFF(MAKEDATE(YEAR(CURRENT_DATE()), DAYOFYEAR(birthdate), CURRENT_DATE()) >= 0
AND   DATEDIFF(MAKEDATE(YEAR(CURRENT_DATE()), DAYOFYEAR(birthdate), CURRENT_DATE()) <= 10
0 голосов
/ 20 мая 2010

Вы можете использовать индекс, если храните день рождения отдельно от даты рождения. Столбец дня рождения будет содержать год и месяц, но у всех будет один и тот же год (например, 2000).

Тогда вы сделаете ваш запрос следующим образом:

SELECT birthdate
FROM Anniversaries
WHERE birthday >= DATE_ADD(MAKEDATE(2000, DAYOFYEAR(CURDATE())), INTERVAL 10 DAYS)

Хотя выражение не совсем то, что вам нужно, число 10 все еще находится с правой стороны выражения. Применение функции к правой стороне выражения и сохранение только столбца в левой части выражения позволяет MySQL использовать индекс для столбца дня рождения (при условии, что у вас есть индекс).

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