При работе с временными диапазонами часто используют
BETWEEN. Но если колонка хранит дату вместе со временем, такой фильтр может возвращать не все ожидаемые записи.Допустим, есть таблица заказов:
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
created_at TIMESTAMP NOT NULL,
amount DECIMAL(12, 2)
);
Нужно получить заказы за сентябрь 2026 года. На первый взгляд подходит запрос:
SELECT *
FROM orders
WHERE created_at BETWEEN
TIMESTAMP '2026-09-01 00:00:00'
AND TIMESTAMP '2026-09-30 00:00:00';
Однако
BETWEEN включает обе границы диапазона и эквивалентен сочетанию >= и <=. Поэтому запрос вернёт записи с 1 сентября по начало 30 сентября, но исключит все заказы, созданные позднее полуночи последнего дня месяца.Например, запись со временем
2026-09-30 15:30:00 не попадёт в результат. Иногда верхнюю границу пытаются исправить вручную:WHERE created_at BETWEEN
TIMESTAMP '2026-09-01 00:00:00'
AND TIMESTAMP '2026-09-30 23:59:59';
Но это тоже ненадёжный вариант. Если колонка поддерживает дробные доли секунды, запись
2026-09-30 23:59:59.500 окажется за пределами диапазона.Для временных интервалов практичнее использовать полуоткрытый диапазон:
SELECT *
FROM orders
WHERE created_at >= TIMESTAMP '2026-09-01 00:00:00'
AND created_at < TIMESTAMP '2026-10-01 00:00:00';
Такой запрос включает все значения за сентябрь независимо от точности хранения времени и исключает записи следующего месяца.
Ещё одно преимущество — соседние интервалы не пересекаются. Например, при последовательной обработке данных можно использовать:
WHERE created_at >= :date_from
AND created_at < :date_to;
При условии, что следующая выборка начинается с предыдущего
date_to, каждая запись на границе интервалов попадёт ровно в один диапазон.Такой подход также хорошо сочетается с обычным B-tree индексом:
CREATE INDEX idx_orders_created_at
ON orders (created_at);
Поскольку фильтрация выполняется непосредственно по индексируемой колонке, оптимизатор может использовать диапазонное сканирование индекса. При использовании типов с часовыми поясами границы необходимо задавать в соответствии с нужной временной зоной, особенно если речь идёт о календарных днях.
🔥 Для фильтрации по временным интервалам условия
>= и < обычно надёжнее, чем BETWEEN. Полуоткрытые диапазоны не зависят от точности TIMESTAMP, не пересекаются на границах и удобны для отчётности, пакетной обработки и инкрементальной загрузки данных.➡️ SQL Ready | #практика