3.3.4.5 Расчеты с датами
MySQL предоставляет несколько функций, которые можно использовать для выполнения расчетов с датами, например, для расчета возраста или извлечения частей дат.
Чтобы определить, сколько лет каждому из ваших питомцев, используйте функцию TIMESTAMPDIFF(). Ее аргументами являются единица измерения результата и две даты, для которых нужно вычислить разницу. Следующий запрос показывает для каждого питомца дату рождения, текущую дату и возраст в годах. Использование псевдонима (age) делает метку последнего столбца вывода более информативной.
mysql> SELECT name, birth, CURDATE(),
TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS age
FROM pet;
+----------+------------+------------+------+
| name | birth | CURDATE() | age |
+----------+------------+------------+------+
| Fluffy | 1993-02-04 | 2003-08-19 | 10 |
| Claws | 1994-03-17 | 2003-08-19 | 9 |
| Buffy | 1989-05-13 | 2003-08-19 | 14 |
| Fang | 1990-08-27 | 2003-08-19 | 12 |
| Bowser | 1989-08-31 | 2003-08-19 | 13 |
| Chirpy | 1998-09-11 | 2003-08-19 | 4 |
| Whistler | 1997-12-09 | 2003-08-19 | 5 |
| Slim | 1996-04-29 | 2003-08-19 | 7 |
| Puffball | 1999-03-30 | 2003-08-19 | 4 |
+----------+------------+------------+------+
Запрос работает, но результаты можно было бы легче просмотреть, если бы строки были представлены в определенном порядке. Это можно сделать, добавив предложение ORDER BY name для сортировки вывода по имени:
mysql> SELECT name, birth, CURDATE(),
TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS age
FROM pet ORDER BY name;
+----------+------------+------------+------+
| name | birth | CURDATE() | age |
+----------+------------+------------+------+
| Bowser | 1989-08-31 | 2003-08-19 | 13 |
| Buffy | 1989-05-13 | 2003-08-19 | 14 |
| Chirpy | 1998-09-11 | 2003-08-19 | 4 |
| Claws | 1994-03-17 | 2003-08-19 | 9 |
| Fang | 1990-08-27 | 2003-08-19 | 12 |
| Fluffy | 1993-02-04 | 2003-08-19 | 10 |
| Puffball | 1999-03-30 | 2003-08-19 | 4 |
| Slim | 1996-04-29 | 2003-08-19 | 7 |
| Whistler | 1997-12-09 | 2003-08-19 | 5 |
+----------+------------+------------+------+
Чтобы отсортировать вывод по age вместо name, просто используйте другое предложение ORDER
BY:
mysql> SELECT name, birth, CURDATE(),
TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS age
FROM pet ORDER BY age;
+----------+------------+------------+------+
| name | birth | CURDATE() | age |
+----------+------------+------------+------+
| Chirpy | 1998-09-11 | 2003-08-19 | 4 |
| Puffball | 1999-03-30 | 2003-08-19 | 4 |
| Whistler | 1997-12-09 | 2003-08-19 | 5 |
| Slim | 1996-04-29 | 2003-08-19 | 7 |
| Claws | 1994-03-17 | 2003-08-19 | 9 |
| Fluffy | 1993-02-04 | 2003-08-19 | 10 |
| Fang | 1990-08-27 | 2003-08-19 | 12 |
| Bowser | 1989-08-31 | 2003-08-19 | 13 |
| Buffy | 1989-05-13 | 2003-08-19 | 14 |
+----------+------------+------------+------+
Аналогичный запрос можно использовать для определения возраста животных при смерти. Вы определяете, о каких животных идет речь, проверяя, имеет ли значение death значение NULL. Затем для тех, у кого значения не NULL, вычислите разницу между значениями death и birth:
mysql> SELECT name, birth, death,
TIMESTAMPDIFF(YEAR,birth,death) AS age
FROM pet WHERE death IS NOT NULL ORDER BY age;
+--------+------------+------------+------+
| name | birth | death | age |
+--------+------------+------------+------+
| Bowser | 1989-08-31 | 1995-07-29 | 5 |
+--------+------------+------------+------+
В запросе используется death IS NOT NULL вместо death <> NULL, потому что NULL — это специальное значение, которое нельзя сравнивать с помощью обычных операторов сравнения. Это обсуждается позже. См. Раздел 3.3.4.6 «Работа с NULL-значениями».
А что, если вы хотите узнать, у каких животных день рождения в следующем месяце? Для этого типа вычислений год и день не имеют значения; вам нужно просто извлечь часть месяца из столбца birth. MySQL предоставляет несколько функций для извлечения частей дат, таких как YEAR(), MONTH() и DAYOFMONTH(). MONTH() — подходящая функция в данном случае. Чтобы увидеть, как она работает, выполните простой запрос, который отображает значение как birth, так и MONTH(birth):
mysql> SELECT name, birth, MONTH(birth) FROM pet;
+----------+------------+--------------+
| name | birth | MONTH(birth) |
+----------+------------+--------------+
| Fluffy | 1993-02-04 | 2 |
| Claws | 1994-03-17 | 3 |
| Buffy | 1989-05-13 | 5 |
| Fang | 1990-08-27 | 8 |
| Bowser | 1989-08-31 | 8 |
| Chirpy | 1998-09-11 | 9 |
| Whistler | 1997-12-09 | 12 |
| Slim | 1996-04-29 | 4 |
| Puffball | 1999-03-30 | 3 |
+----------+------------+--------------+
Нахождение животных с днями рождения в ближайшем месяце тоже просто. Предположим, что текущий месяц — апрель. Тогда значение месяца равно 4, и вы можете искать животных, родившихся в мае (месяц 5), так:
mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+-------+------------+
| name | birth |
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+
Возникает небольшая проблема, если текущий месяц — декабрь. Вы не можете просто добавить единицу к номеру месяца (12) и искать животных, родившихся в месяце 13, потому что такого месяца не существует. Вместо этого вы ищете животных, родившихся в январе (месяц 1).
Вы можете написать запрос, который будет работать независимо от текущего месяца, поэтому вам не нужно использовать число для конкретного месяца. DATE_ADD() позволяет добавлять интервал времени к заданной дате. Если вы добавите месяц к значению CURDATE(), а затем извлечете часть месяца с помощью MONTH(), результат даст месяц, в котором нужно искать дни рождения:
mysql> SELECT name, birth FROM pet
WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));
Другой способ выполнить ту же задачу — добавить 1, чтобы получить следующий месяц после текущего, после использования функции modulo (MOD) для обертывания значения месяца в 0, если оно в настоящее время равно 12:
mysql> SELECT name, birth FROM pet
WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;
MONTH() возвращает число от 1 до 12. А MOD(something,12) возвращает число от 0 до 11. Поэтому сложение должно происходить после MOD(), иначе мы перейдем с ноября (11) на январь (1).
Если расчет использует недействительные даты, расчет не выполняется, и выводятся предупреждения:
mysql> SELECT '2018-10-31' + INTERVAL 1 DAY;
+-------------------------------+
| '2018-10-31' + INTERVAL 1 DAY |
+-------------------------------+
| 2018-11-01 |
+-------------------------------+
mysql> SELECT '2018-10-32' + INTERVAL 1 DAY;
+-------------------------------+
| '2018-10-32' + INTERVAL 1 DAY |
+-------------------------------+
| NULL |
+-------------------------------+
mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1292 | Incorrect datetime value: '2018-10-32' |
+---------+------+----------------------------------------+
© 2025 Oracle
Licensed under the GPLv2 License.