Введение
При работе с реляционными базами данных и языком структурированных запросов (SQL) могут возникать ситуации, когда необходимо работать с значениями, представляющими конкретные даты или времена. Например, вам может потребоваться рассчитать общее количество часов, затраченных на определенную деятельность, или, возможно, вам нужно будет выполнять операции с датами или временными значениями с использованием математических операторов и агрегатных функций для расчета их суммы или среднего значения.
В этом руководстве вы узнаете, как использовать даты и времена в SQL. Вы начнете с выполнения арифметических операций и использования различных функций с датами и временами, используя только оператор SELECT
. Затем вы практиковаться, запуская запросы на образцовых данных, и вы узнаете, как использовать функцию CAST
, чтобы сделать вывод более удобочитаемым.
Предварительные требования
Для завершения этого руководства вам понадобится:
- A server running Ubuntu 20.04, with a non-root user with
sudo
administrative privileges and firewall enabled. Follow our Initial Server Setup with Ubuntu 20.04 to get started. - Установленная и защищенная MySQL на сервере. Следуйте нашему руководству Как установить MySQL на Ubuntu 20.04, чтобы настроить это. При этом руководстве предполагается, что вы также настроили неадминистративного пользователя MySQL, как описано в Шаге 3 этого руководства.
Примечание: Обратите внимание, что многие системы управления реляционными базами данных используют собственные уникальные реализации SQL. Хотя команды, описанные в этом руководстве, будут работать на большинстве СУБД, точный синтаксис или вывод могут отличаться, если вы их протестируете на системе, отличной от MySQL.
Чтобы практиковаться в использовании даты и времени в этом руководстве, вам понадобится база данных и таблица, загруженные образцовыми данными. Если у вас нет готовой базы данных для вставки, вы можете прочитать следующий раздел Подключение к MySQL и настройка образца базы данных, чтобы узнать, как создать базу данных и таблицу. В этом руководстве будет ссылка на эту образцовую базу данных и таблицу.
Подключение к MySQL и настройка образца базы данных
Если ваша база данных SQL запускается на удаленном сервере, выполните вход через SSH на ваш сервер с локального компьютера:
Затем откройте приглашение MySQL, заменив sammy
на информацию о вашей учетной записи MySQL:
Создайте базу данных с именем datetimeDB
:
Если база данных была успешно создана, вы получите следующий вывод:
OutputQuery OK, 1 row affected (0.01 sec)
Чтобы выбрать базу данных datetimeDB
, выполните следующий оператор USE
:
OutputDatabase changed
После выбора базы данных создайте в ней таблицу. В примере этого учебного пособия мы создадим таблицу, которая содержит результаты двух бегунов по различным забегам, которые они провели в течение года. Эта таблица будет иметь следующие семь столбцов:
race_id
: отображает значения типа данныхint
и служит в качестве первичного ключа таблицы, что означает, что каждое значение в этом столбце будет функционировать как уникальный идентификатор для соответствующей строки.-
runner_name
: использует тип данныхvarchar
с максимальной длиной 30 символов для имен двух бегунов, Болта и Феликса. -
race_name
: хранит типы забегов с типом данныхvarchar
с максимальной длиной 20 символов. -
start_day
: использует тип данныхDATE
для отслеживания даты конкретного забега по году, месяцу и дню. Этот тип данных соответствует следующим параметрам: четыре цифры для года и максимум две цифры для месяца и дня (ГГГГ-ММ-ДД
). -
start_time
: представляет время начала забега с типом данныхTIME
по часам, минутам и секундам (ЧЧ:ММ:СС
). Этот тип данных следует формату 24-часовых часов, например,15:00
для эквивалента 15:00. total_miles
: показывает общий пробег для каждой гонки, используя тип данныхdecimal
, поскольку многие значения общего пробега на гонку не являются целыми числами. В этом случаеdecimal
указывает точность до трех знаков с одним знаком справа от десятичной точки.end_time
: использует тип данныхTIMESTAMP
для отслеживания времени финиша бегунов в конце гонки. Этот тип данных объединяет и дату, и время в одной строке, и его формат представляет собой комбинацию форматовDATE
иTIME
: (YYYY-MM-DD HH:MM:SS
).
Создайте таблицу, выполнив команду CREATE TABLE
:
Затем вставьте некоторые образцовые данные в пустую таблицу:
OutputQuery OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0
После вставки данных вы готовы начать практиковать арифметику и функции с датами и временем в SQL.
Использование арифметики с датами и временем
В SQL вы можете выполнять манипуляции с датами и временем, используя математические выражения. Все, что требуется, это математический оператор и значения, которые вы хотите вычислить.
В качестве примера, предположим, вы хотели бы найти дату, которая находится определенное количество дней после другой. Следующий запрос берет одно значение даты (2022-10-05
) и добавляет к нему 17
, чтобы вернуть значение для даты, семнадцать дней после указанной в запросе. Обратите внимание, что в этом примере 2022-10-05
указано как значение DATE
, чтобы обеспечить то, что СУБД не будет интерпретировать его как строку или какой-либо другой тип данных:
Output+----------+
| new_date |
+----------+
| 20221022 |
+----------+
1 row in set (0.01 sec)
Как указывает этот вывод, 17 дней после 2022-10-05
– это 2022-10-22
, или 22 октября 2022 года.
Как еще один пример, предположим, вы хотите рассчитать общее количество часов между двумя разными временами. Вы можете сделать это, вычитая одно время из другого. В следующем запросе 11:00
– это первое значение времени, а 3:00
– второе значение времени. Здесь вам нужно указать, что оба значения являются TIME
, чтобы вернуть разницу в часах:
Output+-----------+
| time_diff |
+-----------+
| 80000 |
+-----------+
1 row in set (0.00 sec)
Этот вывод показывает, что разница между 11:00 и 3:00 – 80000
, или 8 часов.
Теперь попрактикуемся в использовании арифметики с информацией о датах и времени из образца данных. Для первого запроса рассчитайте общее время, затраченное бегунами на завершение каждого забега, вычитая end_time
из start_time
:
Output+-------------+---------------+----------------+
| runner_name | race_name | total_time |
+-------------+---------------+----------------+
| bolt | 1600_meters | 20220918000630 |
| bolt | 5K | 20221019002231 |
| bolt | 10K | 20221120003805 |
| bolt | half_marathon | 20221221013904 |
| bolt | full_marathon | 20230122032310 |
| felix | 1600_meters | 20220918000715 |
| felix | 5K | 20221019003050 |
| felix | 10K | 20221120011017 |
| felix | half_marathon | 20221221021157 |
| felix | full_marathon | 20230122040210 |
+-------------+---------------+----------------+
10 rows in set (0.00 sec)
Вы заметите, что эти значения в столбце total_time
довольно длинные и трудночитаемые. Позднее мы продемонстрируем, как использовать функцию CAST
для преобразования этих значений данных, чтобы они стали более понятными при чтении.
Теперь, если вас интересует только выступление каждого бегуна на более длинных дистанциях, таких как полумарафоны и марафоны, вы можете запросить данные для получения этой информации. Для этого запроса вычтите end_time
из start_time
, и уточните результаты, используя оператор WHERE
, чтобы извлечь данные, где total_miles
были больше 12:
Output+-------------+---------------+-------------------+
| runner_name | race_name | half_full_results |
+-------------+---------------+-------------------+
| bolt | half_marathon | 20221221013904 |
| bolt | full_marathon | 20230122032310 |
| felix | half_marathon | 20221221021157 |
| felix | full_marathon | 20230122040210 |
+-------------+---------------+-------------------+
4 rows in set (0.00 sec)
В этом разделе вы выполнили некоторую арифметику с датами и временем с помощью оператора SELECT
и для практических целей на образцовых данных. Далее вы будете практиковать запросы с использованием различных функций даты и времени.
Использование функций даты и времени и выражений интервала
Существует несколько функций, которые можно использовать для поиска и обработки значений даты и времени в SQL. Функции SQL обычно используются для обработки или манипулирования данными, и доступные функции зависят от реализации SQL. Большинство реализаций SQL, однако, позволяют находить текущую дату и время, запрашивая значения current_date
и current_time
.
Чтобы найти сегодняшнюю дату, например, синтаксис короткий и состоит только из оператора SELECT
и функции current_date
, как в следующем примере:
Output+--------------+
| current_date |
+--------------+
| 2022-02-15 |
+--------------+
1 row in set (0.00 sec)
С использованием того же синтаксиса вы можете найти текущее время с помощью функции current_time
:
Output+--------------+
| current_time |
+--------------+
| 17:10:20 |
+--------------+
1 row in set (0.00 sec)
Если вы предпочитаете запросить и дату, и время в выводе, используйте функцию current_timestamp
:
Output+---------------------+
| current_timestamp |
+---------------------+
| 2022-02-15 19:09:58 |
+---------------------+
1 row in set (0.00 sec)
Вы можете использовать функции даты и времени, подобные тем, что были показаны в предыдущем разделе. Например, скажем, вы хотите узнать, какая была дата 11 дней назад от сегодняшней даты. В этом случае вы можете использовать ту же структуру синтаксиса, которую использовали ранее для запроса функции current_date
, а затем вычесть из нее 11
, чтобы найти дату одиннадцать дней назад:
Output+-------------------+
| current_date - 11 |
+-------------------+
| 20220206 |
+-------------------+
1 row in set (0.01 sec)
Как показывает этот вывод, 11 дней назад от current_date
(на момент написания этого текста) было 2022-02-06
, или 6 февраля 2022 года. Теперь попробуйте выполнить ту же операцию, но замените функцию current_date
на функцию current_time
:
Output+-------------------+
| current_time - 11 |
+-------------------+
| 233639 |
+-------------------+
1 row in set (0.00 sec)
Этот вывод показывает, что при вычитании 11
из значения current_time
вычитаются 11 секунд. Операция, которую вы выполняли ранее с использованием функции current_date
, интерпретировала 11
как дни, а не секунды. Эта несогласованность в интерпретации чисел при работе с функциями даты и времени может быть запутывающей. Вместо того чтобы требовать от вас манипулировать значениями даты и времени с использованием арифметики, как это было ранее, многие системы управления базами данных позволяют быть более явными с помощью выражений INTERVAL
.
Выражения INTERVAL
позволяют найти, какая будет дата или время до или после заданного интервала от заданного выражения даты или времени. Они должны иметь следующую форму:
INTERVAL value unit
Например, чтобы найти дату через пять дней от сегодняшнего дня, вы можете выполнить следующий запрос:
Этот пример находит значение current_date
, а затем добавляет к нему выражение интервала INTERVAL '5' DAY
. Это возвращает дату, отстоящую на 5 дней от текущей:
Output+-------------------+
| 5_days_from_today |
+-------------------+
| 2022-03-06 |
+-------------------+
1 row in set (0.00 sec)
Этот способ гораздо менее двусмысленный, чем следующий запрос, который дает аналогичный, хотя и не идентичный результат:
Output+-------------------+
| 5_days_from_today |
+-------------------+
| 20220306 |
+-------------------+
1 row in set (0.00 sec)
Обратите внимание, что вы также можете вычитать интервалы из дат или времени, чтобы найти значения, предшествующие указанной дате:
Output+--------------+
| 7_months_ago |
+--------------+
| 2021-08-01 |
+--------------+
1 row in set (0.00 sec)
Доступные единицы измерения для использования в выражениях INTERVAL
зависят от вашей выбора СУБД, хотя большинство из них будут иметь опции, такие как HOUR
, MINUTE
и SECOND
:
Output+------------------+---------------+---------------------+
| 6_hours_from_now | 5_minutes_ago | 20_seconds_from_now |
+------------------+---------------+---------------------+
| 07:51:43 | 01:46:43 | 01:52:03.000000 |
+------------------+---------------+---------------------+
1 row in set (0.00 sec)
Теперь, когда вы узнали о выражениях интервалов и некоторых функциях даты и времени, продолжайте практиковаться с обработкой примерных данных, которые вы вставили на первом этапе.
Использование CAST и агрегатных функций с датой и временем
Вспомните третий пример из раздела Использование арифметики с датами и временем, когда вы выполняли следующий запрос для вычитания end_time
из start_time
для расчета общего количества часов, которое каждый бегун завершил за забег. Однако вывод оказался в столбце с очень длинным результатом, следующим за типом данных TIMESTAMP
, который был установлен в таблице:
Output+-------------+---------------+----------------+
| runner_name | race_name | total_time |
+-------------+---------------+----------------+
| bolt | 1600_meters | 20220918000630 |
| bolt | 5K | 20221019002231 |
| bolt | 10K | 20221120003805 |
| bolt | half_marathon | 20221221013904 |
| bolt | full_marathon | 20230122032310 |
| felix | 1600_meters | 20220918000715 |
| felix | 5K | 20221019003050 |
| felix | 10K | 20221120011017 |
| felix | half_marathon | 20221221021157 |
| felix | full_marathon | 20230122040210 |
+-------------+---------------+----------------+
10 rows in set (0.00 sec)
Поскольку вы выполняете операцию с двумя столбцами, имеющими разные типы данных (end_time
, содержащий значения типа TIMESTAMP
, и start_time
, содержащий значения типа TIME
), база данных не знает, какой тип данных использовать при выводе результата операции. Вместо этого она преобразует оба значения в целые числа, чтобы выполнить операцию, что приводит к длинным числам в столбце total_time
.
Чтобы сделать эти данные более понятными для чтения и интерпретации, вы можете использовать функцию CAST
для преобразования этих длинных целочисленных значений в тип данных TIME
. Для этого начните с CAST
, а затем следуйте немедленно за ним открывающей скобкой, значениями, которые вы хотите преобразовать, и затем ключевым словом AS
и типом данных, в который вы хотите преобразовать его.
Следующий запрос идентичен предыдущему примеру, но использует функцию CAST
для преобразования столбца total_time
в тип данных time
:
Output+-------------+---------------+------------+
| runner_name | race_name | total_time |
+-------------+---------------+------------+
| bolt | 1600_meters | 00:06:30 |
| bolt | 5K | 00:22:31 |
| bolt | 10K | 00:38:05 |
| bolt | half_marathon | 01:39:04 |
| bolt | full_marathon | 03:23:10 |
| felix | 1600_meters | 00:07:15 |
| felix | 5K | 00:30:50 |
| felix | 10K | 01:10:17 |
| felix | half_marathon | 02:11:57 |
| felix | full_marathon | 04:02:10 |
+-------------+---------------+------------+
10 rows in set (0.00 sec)
CAST
преобразовала данные в тип TIME
в этом выводе, что делает его намного более удобочитаемым для чтения и понимания.
Теперь давайте используем несколько агрегатных функций в сочетании с функцией CAST
, чтобы найти самые короткие, самые длинные и общие результаты времени каждого бегуна. Сначала запросим минимальное (или самое короткое) количество времени с использованием агрегатной функции MIN
. Снова вам потребуется использовать CAST
для преобразования значений данных TIMESTAMP
в значения данных TIME
для ясности. Обратите внимание, что при использовании двух функций, как в этом примере, требуются две пары скобок, а вычисление общего количества часов (end_time - start_time
) должно быть вложено в одну из них. Наконец, добавьте GROUP BY
клаузу для организации этих значений на основе столбца runner_name
, чтобы вывод отображал результаты гонки двух бегунов:
Output+-------------+----------+
| runner_name | min_time |
+-------------+----------+
| bolt | 00:06:30 |
| felix | 00:07:15 |
+-------------+----------+
2 rows in set (0.00 sec)
Этот вывод показывает самое короткое время каждого бегуна, в данном случае минимальное – шесть минут и 30 секунд для Болта и семь минут и 15 секунд для Феликс.
Затем найдем самое длительное время каждого бегуна. Вы можете использовать тот же синтаксис, что и в предыдущем запросе, но на этот раз замените MIN
на MAX
:
Output+-------------+----------+
| runner_name | max_time |
+-------------+----------+
| bolt | 03:23:10 |
| felix | 04:02:10 |
+-------------+----------+
2 rows in set (0.00 sec)
Этот вывод говорит нам, что самое длительное время Болта составило три часа, 23 минуты и 10 секунд; и Феликс – четыре часа, две минуты и 10 секунд.
Теперь давайте запросим некоторую общую информацию о общем количестве часов, которые каждый бегун потратил на бег. Для этого объедините агрегатную функцию SUM
, чтобы найти общую сумму часов на основе end_time - start_time
, и используйте CAST
, чтобы преобразовать эти данные в тип TIME
. Не забудьте включить GROUP BY
, чтобы организовать значения для результатов обоих бегунов:
Output+-------------+-------------+
| runner_name | total_hours |
+-------------+-------------+
| bolt | 52880 |
| felix | 76149 |
+-------------+-------------+
2 rows in set (0.00 sec)
Интересно, что эти результаты показывают интерпретацию для MySQL, который фактически вычисляет общее время как целые числа. Если мы читаем эти результаты как время, общее время Болта распадается на пять часов, 28 минут и 80 секунд; время Феликса разбивается на семь часов, 61 минуту и 49 секунд. Как видите, эта декомпозиция времени не имеет смысла, что указывает на то, что она вычисляется как целое число, а не как время. Если бы вы попробовали это сделать в другой СУБД, например, в PostgreSQL, то тот же запрос выглядел бы немного иначе:
Output runner_name | total_hours
-------------+-------------
felix | 10:01:44
bolt | 06:09:20
(2 rows)
В этом случае запрос в PostgreSQL интерпретирует значения как время и вычисляет их соответственно, так что результаты Феликса разбиваются на общее время в 10 часов, одну минуту и 44 секунды; а для Болта – шесть часов, девять минут и 20 секунд. Это пример того, как различные реализации СУБД могут по-разному интерпретировать значения данных, даже если используется тот же запрос и набор данных.
Заключение
Понимание того, как использовать дату и время в SQL, полезно при запросе конкретных результатов, таких как минуты, секунды, часы, дни, месяцы, годы; или их комбинация. Кроме того, существует множество функций для работы с датами и временем, которые упрощают поиск определенных значений, таких как текущая дата или время. Хотя в этом руководстве использовались только арифметические операции сложения и вычитания с датами и временем в SQL, вы можете использовать значения даты и времени с любым математическим выражением. Узнайте больше из нашего руководства по математическим выражениям и агрегатным функциям и попробуйте их в своих запросах даты и времени.
Source:
https://www.digitalocean.com/community/tutorials/how-to-work-with-dates-and-times-in-sql