Формат дат и времени
Даты в SQL часто приходят в плохом виде: как текст, в разных форматах. Если не привести их к DATE или TIMESTAMP, сортировка и расчёты будут неверными.
В этом уроке работаем с таблицами tutorial.crunchbase_companies_clean_date и tutorial.crunchbase_acquisitions_clean_date.
Почему год идёт первым
Заголовок раздела «Почему год идёт первым»Американский формат М/Д/ГГ (например 9/4/14) удобен человеку. Но как текст он не сортируется по времени. Текст сравнивается по символам слева направо.
SELECT permalink, founded_atFROM tutorial.crunchbase_companies_clean_dateWHERE founded_at IS NOT NULLORDER BY founded_atLIMIT 5;Первыми придут строки, которые начинаются с 1/1/00. Потом 1/1/01… Но 1/30/15 будет раньше, чем 2/1/05. Порядок неверный.
Формат ГГГГ-ММ-ДД решает проблему. Текст в этом формате сортируется так же, как даты:
SELECT permalink, founded_at, founded_at_cleanFROM tutorial.crunchbase_companies_clean_dateWHERE founded_at IS NOT NULLORDER BY founded_at_cleanLIMIT 5;Арифметика с датами
Заголовок раздела «Арифметика с датами»Разница двух дат или timestamp — это тип INTERVAL. Колонка founded_at_clean это текст. Поэтому сначала приведите её к TIMESTAMP.
Сколько времени прошло от основания до продажи компании:
SELECT companies.permalink, companies.founded_at_clean, acquisitions.acquired_at_cleaned, acquisitions.acquired_at_cleaned - companies.founded_at_clean::TIMESTAMP AS time_to_acquisitionFROM tutorial.crunchbase_companies_clean_date companiesJOIN tutorial.crunchbase_acquisitions_clean_date acquisitions ON acquisitions.company_permalink = companies.permalinkWHERE companies.founded_at_clean IS NOT NULL;Результат — интервал в днях, например 1336 days.
INTERVAL
Заголовок раздела «INTERVAL»Интервал можно записать словами: '1 week', '3 years', '10 seconds'. Дата плюс интервал даёт новую дату:
SELECT permalink, founded_at_clean, founded_at_clean::TIMESTAMP + INTERVAL '1 week' AS plus_one_weekFROM tutorial.crunchbase_companies_clean_dateWHERE founded_at_clean IS NOT NULLLIMIT 5;Текущее время
Заголовок раздела «Текущее время»now() возвращает текущий момент:
SELECT permalink, founded_at_clean, now() - founded_at_clean::TIMESTAMP AS founded_time_agoFROM tutorial.crunchbase_companies_clean_dateWHERE founded_at_clean IS NOT NULLLIMIT 5;Результат зависит от дня запуска. Это нормально.
Полезные функции DuckDB
Заголовок раздела «Полезные функции DuckDB»| Задача | DuckDB | Результат |
|---|---|---|
| Формат даты в текст | strftime(d, '%d.%m.%Y') | 05.03.2014 |
| Часть даты | date_part('year', d) или EXTRACT(year FROM d) | 2014 |
| Разница в днях | date_diff('day', d1, d2) | 59 |
| Разница «как у человека» | age(d2, d1) | 2 years 1 month 17 days |
| Начало месяца | date_trunc('month', d) | 2014-03-01 |
| Текст в дату | strptime('03/05/2014', '%m/%d/%Y') | 2014-03-05 |
SELECT strftime(DATE '2014-03-05', '%d.%m.%Y') AS formatted, date_part('year', DATE '2014-03-05') AS year, date_diff('day', DATE '2014-01-01', DATE '2014-03-01') AS days, age(DATE '2014-03-01', DATE '2012-01-15') AS human_age, date_trunc('month', DATE '2014-03-05') AS month_start;Практика
Заголовок раздела «Практика»Решайте сами, без AI. Сначала напишите запрос, потом сверьтесь с проверкой, и только потом открывайте решение.
Задание 1
Заголовок раздела «Задание 1»Напишите запрос, который считает компании, проданные в течение 3, 5 и 10 лет после основания. Каждый срок — в отдельной колонке. Добавьте колонку с общим числом проданных компаний. Группируйте по category_code. Берите только компании с датой основания. Покажите сначала категории с самым большим общим числом.
Проверка: 331 строка. Первая строка: software — 44, 92, 270 и всего 470.
Решение
SELECT companies.category_code, COUNT(CASE WHEN acquisitions.acquired_at_cleaned <= companies.founded_at_clean::TIMESTAMP + INTERVAL '3 years' THEN 1 END) AS acquired_3_yrs, COUNT(CASE WHEN acquisitions.acquired_at_cleaned <= companies.founded_at_clean::TIMESTAMP + INTERVAL '5 years' THEN 1 END) AS acquired_5_yrs, COUNT(CASE WHEN acquisitions.acquired_at_cleaned <= companies.founded_at_clean::TIMESTAMP + INTERVAL '10 years' THEN 1 END) AS acquired_10_yrs, COUNT(1) AS totalFROM tutorial.crunchbase_companies_clean_date companiesJOIN tutorial.crunchbase_acquisitions_clean_date acquisitions ON acquisitions.company_permalink = companies.permalinkWHERE companies.founded_at_clean IS NOT NULLGROUP BY 1ORDER BY 5 DESC;