Даты и время: вопросы для собеседования (часть 3)
Работа с датами в SQL — это DATE_TRUNC, EXTRACT, интервалы, приведение типов и группировка по временным периодам. На собеседованиях часто просят посчитать метрику по неделям или месяцам, найти разницу между датами, или отфильтровать данные за скользящее окно. Ошибки в работе с таймзонами и форматами дат — частая причина провала на интервью.
Вопросы 11–15 из 20
11Какое утверждение верно про `DATE_TRUNC('week', ts)` в PostgreSQL (где `ts` типа `timestamp`)?
AВсегда возвращает воскресенье `00:00:00` той недели.
BВозвращает номер недели как целое число.
CСбрасывает только часы, но сохраняет день недели.
DВозвращает метку времени начала недели (понедельник `00:00:00`) для значения `ts`.
Ответ: `DATE_TRUNC('week', ...)` даёт начало недельного бакета; в PostgreSQL неделя начинается в понедельник.
В PostgreSQL `DATE_TRUNC('week', ts)` возвращает начало ISO-недели: понедельник `00:00:00`. Это удобно для недельной группировки и периодных сравнений.
12Для сравнения период-к-периоду нужно получить начало прошлого календарного месяца. Какое выражение вернёт начало прошлого месяца?
A`DATE_TRUNC('day', current_date) - INTERVAL '1 month'`
B`DATE_TRUNC('month', current_date) - INTERVAL '30 days'`
C`current_date - INTERVAL '1 month'`
D`DATE_TRUNC('month', current_date) - INTERVAL '1 month'`
Ответ: Чтобы получить границу календарного периода, сначала используйте `DATE_TRUNC`, затем сдвигайте через `INTERVAL`.
Чтобы взять ровно прошлый календарный месяц, сначала найдите начало текущего месяца `DATE_TRUNC('month', current_date)`, затем сдвиньте границу на месяц назад: `- INTERVAL '1 month'`. Вариант с `- INTERVAL '30 days'` может дать неверную границу, потому что длина месяцев разная.
13В таблице `users(signup_at)` поле `signup_at` типа `date`. Нужно получить дату «через один календарный месяц» после регистрации. Какое выражение корректнее?
A`signup_at + INTERVAL '30 days'`
B`signup_at + INTERVAL '4 weeks'`
C`signup_at + INTERVAL '1 month'`
D`DATE_TRUNC('month', signup_at) + INTERVAL '1 month'`
Ответ: Календарные месяцы корректнее считать через `INTERVAL '1 month'`, а не фиксированное число дней.
`INTERVAL '30 days'` и `INTERVAL '4 weeks'` — фиксированное количество дней, которое не совпадает с календарным месяцем. Если бизнес-правило звучит как «через месяц», используйте `+ INTERVAL '1 month'`. В Postgres выражение `date + interval` возвращает `timestamp` (обычно с временем `00:00:00`); при необходимости приведите результат к `::date`. Вариант с `DATE_TRUNC('month', signup_at)` сдвигает дату к началу месяца и меняет смысл расчёта.
14Вы строите дневной бакет `DATE_TRUNC('day', created_at) AS day`. Какое выражение даст ключ для `JOIN` на «тот же день прошлой недели»?
A`DATE_TRUNC('day', created_at) - INTERVAL '1 day'`
B`DATE_TRUNC('day', created_at) - INTERVAL '1 week'`
C`DATE_TRUNC('week', created_at) - INTERVAL '1 week'`
D`DATE_TRUNC('day', created_at) + INTERVAL '1 week'`
Ответ: Для сопоставления по дням сдвигайте уже усечённый дневной бакет на `INTERVAL '1 week'`.
Если ключом является начало дня (`DATE_TRUNC('day', ...)`), то для периода-к-периоду удобнее сдвигать этот ключ: `- INTERVAL '1 week'`. Сдвиг недельного бакета (`DATE_TRUNC('week', ...)`) даст начало недели, а не тот же день недели.
15Нужно отобрать заказы за текущий календарный месяц по `created_at` (тип `timestamp`). Какое условие в `WHERE` корректно и обычно лучше использует индекс по `created_at`?
A`WHERE created_at >= current_date - INTERVAL '30 days'`
B`WHERE created_at >= DATE_TRUNC('month', current_date) AND created_at < DATE_TRUNC('month', current_date) + INTERVAL '1 month'`
C`WHERE DATE_TRUNC('month', created_at) = DATE_TRUNC('month', current_date)`
D`WHERE created_at >= DATE_TRUNC('month', current_date) + INTERVAL '1 month'`
Ответ: Для календарного месяца используйте диапазон `[start_of_month, start_of_next_month)` без функции на колонке.
Выражение `DATE_TRUNC('month', created_at) = ...` часто заставляет СУБД применять функцию к каждой строке и может мешать использовать индекс. Диапазон `created_at >= start AND created_at < start + INTERVAL '1 month'` обычно быстрее и однозначно задаёт границы месяца.
Хотите тренировать интерактивно?
В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.
Тренировать в Telegram