Spec-Zone.ru › MySQL 5.7

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.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/date-calculations.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API