Даты и время: вопросы для собеседования (часть 3)

Работа с датами в SQL — это DATE_TRUNC, EXTRACT, интервалы, приведение типов и группировка по временным периодам. На собеседованиях часто просят посчитать метрику по неделям или месяцам, найти разницу между датами, или отфильтровать данные за скользящее окно. Ошибки в работе с таймзонами и форматами дат — частая причина провала на интервью.

Агрегация, GROUP BY и HAVINGEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции

Вопросы 1115 из 20

11Какое утверждение верно про `DATE_TRUNC('week', ts)` в PostgreSQL (где `ts` имеет тип `timestamp`)?
AВсегда возвращает воскресенье `00:00:00` той недели, независимо от настроек `lc_time` и часового пояса сервера
BВозвращает номер недели как целое число от 1 до 53, как функция `EXTRACT(week FROM ts)` в PostgreSQL
CСбрасывает только часы и минуты в `ts`, но сохраняет исходный день недели и значения секунд без изменений
DВозвращает метку времени начала недели (понедельник `00:00:00`) для значения `ts` в типе `timestamp`
Ответ: `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'`: фиксированный сдвиг на 30 дней в качестве приближения к месяцу
B`signup_at + INTERVAL '4 weeks'`: сдвиг на 28 дней через интервал в неделях вместо календарного месяца
C`signup_at + INTERVAL '1 month'`: календарный сдвиг на месяц с учётом длины конкретного месяца
D`DATE_TRUNC('month', signup_at) + INTERVAL '1 month'`: выражение возвращает первое число следующего месяца
Ответ: Календарные месяцы корректнее считать через `INTERVAL '1 month'`, а не фиксированное число дней или недель.

`INTERVAL '30 days'` и `INTERVAL '4 weeks'` — это фиксированные числа дней (30 и 28), которые не совпадают с календарным месяцем — он бывает 28, 29, 30 или 31 день. Если бизнес-правило звучит как «через месяц», корректнее использовать `+ INTERVAL '1 month'`: Postgres сам учтёт длину месяца. Выражение `signup_at + INTERVAL '1 month'` возвращает `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'`: фильтр последних 30 дней, а не календарного месяца
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'`: фильтр будущего месяца без подходящих заказов
Ответ: Для текущего календарного месяца используйте полуинтервал `[начало месяца, начало следующего месяца)` без функции на колонке.

Выражение `DATE_TRUNC('month', created_at) = ...` часто заставляет СУБД применять функцию к каждой строке и может мешать использовать индекс. Диапазон `created_at >= start AND created_at < start + INTERVAL '1 month'` обычно быстрее и однозначно задаёт границы месяца.

Подробный разбор →
1234

Хотите тренировать интерактивно?

В приложении — таймер, прогресс, стрики и 1700+ вопросов по всем темам.

Тренировать SQL в Telegram

Другие темы: SQL

Агрегация, GROUP BY и HAVINGEXPLAIN и оптимизацияВыражения и NULLJOIN и операции множествОсновы SQL-запросовСтроки и приведение типовПодзапросы и CTEОконные функции