Даты и время: вопросы для собеседования (часть 2)
Работа с датами в SQL — это DATE_TRUNC, EXTRACT, интервалы, приведение типов и группировка по временным периодам. На собеседованиях часто просят посчитать метрику по неделям или месяцам, найти разницу между датами, или отфильтровать данные за скользящее окно. Ошибки в работе с таймзонами и форматами дат — частая причина провала на интервью.
Вопросы 6–10 из 20
6Колонка `created_at` имеет тип `timestamp`. Какой тип данных вернёт `DATE_TRUNC('day', created_at)`?
AТип `timestamp`: время будет `00:00:00` для выбранного дня, тип входа сохраняется на выходе
BТип `date`: только календарная дата без компоненты времени, остаётся одно значение даты
CЦелое число `int`: порядковый номер дня в месяце, полученный из исходного значения `timestamp`
DСтроку формата `'YYYY-MM-DD'`: текстовое представление даты в типе `text` или `varchar`
Ответ: `DATE_TRUNC` сохраняет тип `timestamp` и обнуляет более мелкие компоненты времени.
При входе типа `timestamp` результат `DATE_TRUNC('day', created_at)` тоже будет `timestamp`, но с временем начала дня `00:00:00`. Если нужен именно `date`, добавьте приведение `created_at::date` или оборачивайте `DATE_TRUNC` в `CAST`. Целое число или строка — типы, которые `DATE_TRUNC` не возвращает.
Подробный разбор → 7Колонка `created_at` типа `timestamp`. Какое утверждение про `created_at::date` и `DATE_TRUNC('day', created_at)` верно?
A`created_at::date` отдаёт `timestamp`, а `DATE_TRUNC('day', created_at)` отдаёт `date`
B`created_at::date` возвращает тип `date`, а `DATE_TRUNC('day', created_at)` возвращает `timestamp`
C`DATE_TRUNC('day', created_at)` округляет до ближайшего дня, а `created_at::date` обрезает время
DОба выражения возвращают тип `date` и одинаковое значение для любых входных `timestamp`
Ответ: Приведение `::date` меняет тип, а `DATE_TRUNC` сохраняет `timestamp` и обнуляет время ниже указанной гранулярности.
При `created_at::date` вы получаете календарную дату без времени, тип результата — `date`. `DATE_TRUNC('day', created_at)` возвращает `timestamp` на `00:00:00` этого дня, тип сохраняется. Это влияет на формат результата и на дальнейшие сравнения и вычисления — например, при `JOIN` по дате типы должны совпадать.
Подробный разбор → 8Есть таблица `orders(created_at, amount)`, где `created_at` имеет тип `timestamp`. Как посчитать выручку по месяцам?
A`SELECT DATE_TRUNC('month', created_at) AS m, SUM(amount) FROM orders GROUP BY DATE_TRUNC('month', created_at);`
B`SELECT DATE_TRUNC('month', created_at) AS m, amount FROM orders GROUP BY DATE_TRUNC('month', created_at);`
C`SELECT DATE_TRUNC('month', created_at) AS m, SUM(amount) FROM orders ORDER BY DATE_TRUNC('month', created_at);`
D`SELECT DATE_TRUNC('day', created_at) AS m, SUM(amount) FROM orders GROUP BY DATE_TRUNC('month', created_at);`
Ответ: Для метрик по периодам вычислите бакет через `DATE_TRUNC` и агрегируйте с `GROUP BY` по этому бакету.
Чтобы получить выручку по месяцам, сформируйте месячный бакет `DATE_TRUNC('month', created_at)` и посчитайте `SUM(amount)`. В `GROUP BY` нужно повторить то же выражение, что используется для бакета. Без агрегата `SUM` будет просто список заказов, а с днём в `SELECT` и месяцем в `GROUP BY` запрос вернёт ошибку или некорректный результат.
Подробный разбор → 9В таблице `events(created_at)` нужно выбрать события за последние 7 дней с точностью до текущего момента (включая сегодняшние, ещё не завершённые сутки). Какое условие в `WHERE` корректнее?
A`WHERE created_at >= current_timestamp - INTERVAL '7 days'`
B`WHERE created_at >= current_date - INTERVAL '7 days'`
C`WHERE DATE_TRUNC('day', created_at) >= current_timestamp - INTERVAL '7 days'`
D`WHERE created_at <= current_timestamp - INTERVAL '7 days'`
Ответ: Для скользящего окна «последние 7 дней до текущего момента» используют `current_timestamp - INTERVAL '7 days'`.
`current_timestamp` возвращает момент с временем, поэтому `created_at >= current_timestamp - INTERVAL '7 days'` отбирает события за последние 7×24 часа. `current_date` обнуляет время до полуночи и подходит для календарных периодов («с начала дня семь дней назад»), но смещает границу окна. Вариант с `DATE_TRUNC` сравнивает день с моментом времени и теряет внутренний интервал. Условие `<=` берёт всё старше 7 дней, то есть зеркально неправильное окно.
Подробный разбор → 10Для сравнения метрик по неделям нужно получить начало предыдущей недели. Какое выражение вернёт начало предыдущей недели относительно `current_date`?
A`DATE_TRUNC('week', current_date) - INTERVAL '1 week'`
B`DATE_TRUNC('week', current_date) - INTERVAL '1 day'`
C`DATE_TRUNC('month', current_date) - INTERVAL '1 week'`
D`current_date - INTERVAL '1 week'`
Ответ: Найдите начало текущей недели через `DATE_TRUNC`, затем сдвиньте на `INTERVAL '1 week'` назад.
Чтобы корректно сравнивать недели, важно фиксировать границы бакетов. `DATE_TRUNC('week', current_date)` даёт начало текущей недели, а `- INTERVAL '1 week'` — начало предыдущей.
Подробный разбор →