Как выбрать записи за последние 45 дней в разных СУБД

Узнайте, как легко формировать запросы за 45 дней в MySQL, PostgreSQL, SQL Server и Oracle, избегая типичных ошибок и ускоряя работу с данными.

В реальных проектах часто требуется отобрать записи, которые были созданы или изменены за определённый период времени; Одним из самых популярных диапазонов является «за последние 45 дней». В этой статье мы разберём, как сформировать такие запросы в разных СУБД (MySQL, PostgreSQL, Microsoft SQL Server, Oracle) и какие нюансы следует учитывать для корректной работы и высокой производительности.

Общие принципы работы с датой в SQL

  • Типы данных – DATE, DATETIME, TIMESTAMP, TIME. Выбирайте тип, соответствующий точности, которую вам нужен.
  • Функции получения текущей даты/времени – NOW, CURRENT_DATE, GETDATE, SYSTIMESTAMP и т.д.
  • Операторы интервала – INTERVAL (MySQL, PostgreSQL), DATEADD (SQL Server), NUMTODSINTERVAL (Oracle).
  • Функции сравнения – DATEDIFF, DATE_PART, EXTRACT и др.

Для получения диапазона «за последние 45 дней» нам нужны две даты:

  1. Текущая дата/время (верхняя граница).
  2. Дата, отстоящая от текущей на 45 дней назад (нижняя граница).

Далее мы будем использовать эти две границы в условии WHERE с помощью разных синтаксисов.

MySQL / MariaDB

Самый простой вариант

SELECT *
FROM orders
WHERE order_date >= CURDATE ー INTERVAL 45 DAY
 AND order_date < CURDATE + INTERVAL 1 DAY; -- включаем сегодняшние записи

Пояснения:

  • CURDATE возвращает текущую дату без времени.
  • Выражение CURDATE ー INTERVAL 45 DAY даёт дату 45 дней назад.
  • В условии >= и < мы получаем полные 45 дней, включая сегодня.

С учётом времени (DATETIME / TIMESTAMP)

SELECT *
FROM logs
WHERE log_timestamp BETWEEN NOW ⎯ INTERVAL 45 DAY AND NOW;

Функция NOW возвращает текущий момент (дата + время), поэтому диапазон будет точным до секунды.

Использование DATE_SUB (альтернатива)

SELECT *
FROM events
WHERE event_date >= DATE_SUB(CURDATE, INTERVAL 45 DAY);

Индексирование

Если колонка order_date (или другая дата) имеет индекс, запрос будет использовать диапазонный поиск, что обеспечивает быстрый отклик даже на больших таблицах.

PostgreSQL

Функция CURRENT_DATE и оператор INTERVAL

SELECT *
FROM sales
WHERE sale_date >= (CURRENT_DATE ー INTERVAL '45 days')
 AND sale_date < (CURRENT_DATE + INTERVAL '1 day');

Точнее – с NOW (TIMESTAMP)

SELECT *
FROM activity
WHERE activity_ts BETWEEN NOW ー INTERVAL '45 days' AND NOW;

Функция AGE и DATE_TRUNC

Если нужно сравнить только по дате без времени, удобно обрезать метку времени:

SELECT *
FROM visits
WHERE DATE_TRUNC('day', visit_ts) 
 BETWEEN (CURRENT_DATE ⎯ INTERVAL '45 days')
 AND CURRENT_DATE;

Индексы и BRIN

Для огромных таблиц с датой удобно использовать BRIN-индекс:

CREATE INDEX idx_visits_ts_brin
 ON visits USING BRIN (visit_ts);

Он ускорит диапазонные запросы, такие как «за последние 45 дней».

Microsoft SQL Server (T‑SQL)

Функция GETDATE + DATEADD

SELECT *
FROM dbo.Purchases
WHERE PurchaseDate >= DATEADD(day, -45, CAST(GETDATE AS DATE))
 AND PurchaseDate < CAST(GETDATE AS DATE) + 1; -- включаем сегодня

Если колонка хранит datetime2 (время тоже)

SELECT *
FROM dbo.Events
WHERE EventDateTime BETWEEN DATEADD(day, -45, GETDATE) AND GETDATE;

Использование DATEDIFF (не рекомендуется для индексов)

Вариант, который часто встречается в примерах, но приводит к сканированию таблицы:

-- НЕ ПОЛУЧИТЕ ИНДЕКС! Лучше использовать диапазон, как выше.
SELECT *
FROM dbo.Orders
WHERE DATEDIFF(day, OrderDate, GETDATE) <= 45;

Индексирование

Создайте обычный B‑tree индекс по колонке даты:

CREATE INDEX idx_orders_date ON dbo.Orders (OrderDate);

Тогда запрос с диапазоном (>= … AND < …) будет использовать seek‑операцию.

Oracle

Текущая дата – SYSDATE

SELECT *
FROM employees

WHERE hire_date BETWEEN SYSDATE ー 45 AND SYSDATE;

В Oracle интервал в днях задаётся просто числом, поэтому SYSDATE ー 45 уже даёт дату 45 дней назад.

Точнее – с INTERVAL и TIMESTAMP

SELECT *
FROM logs
WHERE log_ts BETWEEN SYSTIMESTAMP ⎯ INTERVAL '45' DAY
 AND SYSTIMESTAMP;

Приведение к дате без времени

Если колонка хранит TIMESTAMP, а нам нужны только даты, используем TRUNC:

SELECT *
FROM visits
WHERE TRUNC(visit_ts) BETWEEN TRUNC(SYSDATE) ー 45 AND TRUNC(SYSDATE);

Индексы

Создайте обычный B‑tree индекс по колонке даты:

CREATE INDEX idx_visits_ts ON visits (visit_ts);

Если запрос часто использует TRUNC(visit_ts), лучше создать функциональный индекс:

CREATE INDEX idx_visits_ts_trunc ON visits (TRUNC(visit_ts));

Общие рекомендации по производительности

  1. Используйте диапазонные условия (col BETWEEN … AND … или col >= … AND col < …). Они позволяют СУБД применять индексы.
  2. Избегайте функций над колонкой (например, DATEDIFF(col, …) в SQL Server). Такие конструкции заставляют СУБД выполнять полное сканирование.
  3. Проверяйте план выполнения (EXPLAIN, EXPLAIN ANALYZE, SET SHOWPLAN_ALL ON и т.п.) чтобы убедиться, что используется индекс.
  4. Если требуется только дата без времени, храните её в типе DATE или создавайте функциональный индекс по TRUNC(col) / CAST(col AS DATE).
  5. Периодическое обновление статистики помогает оптимизатору выбирать правильный план.

Полный набор примеров в виде таблицы

СУБД Текущая дата/время Запрос (дата без времени) Запрос (время учитывается)
MySQL CURDATE / NOW WHERE dt >= CURDATE ー INTERVAL 45 DAY WHERE dt BETWEEN NOW ー INTERVAL 45 DAY AND NOW
PostgreSQL CURRENT_DATE / NOW WHERE dt >= (CURRENT_DATE ⎯ INTERVAL '45 days') WHERE dt BETWEEN NOW ー INTERVAL '45 days' AND NOW
SQL Server GETDATE WHERE dt >= DATEADD(day, -45, CAST(GETDATE AS DATE)) WHERE dt BETWEEN DATEADD(day, -45, GETDATE) AND GETDATE
Oracle SYSDATE / SYSTIMESTAMP WHERE dt BETWEEN SYSDATE ー 45 AND SYSDATE WHERE dt BETWEEN SYSTIMESTAMP ー INTERVAL '45' DAY AND SYSTIMESTAMP

Запросы «за последние 45 дней» одинаково просты во всех популярных СУБД, но детали синтаксиса отличаються. Главное – помнить о двух вещах:

  1. Определить правильный верхний и нижний предел с помощью функций NOW, CURRENT_DATE, GETDATE и операторов INTERVAL / DATEADD.
  2. Сделать так, чтобы условие сравнения использовало колонку «как есть», а не её результат функции – тогда СУБД сможет задействовать индекс и запрос выполнится быстро.

Следуя этим рекомендациям, вы сможете без проблем получать нужные данные за любые динамические периоды, в т.ч. за последние 45 дней.