Как правильно использовать синтаксис BETWEEN в SQL
Что проверяют
Знаете ли вы, что BETWEEN включает обе границы, и понимаете ли, где это ломает отчёты. Для аналитика главный подвох в датах и времени, поэтому следом почти всегда просят выбрать данные за месяц по колонке с типом timestamp.
Как отвечать
x BETWEEN a AND b это ровно x >= a AND x <= b. Дальше детали:
- порядок границ: при
a > bусловие не вернёт ни одной строки. В PostgreSQL естьBETWEEN SYMMETRIC, который сам меняет границы местами, но в переносимом запросе на это не полагаются; - даты и время:
created_at BETWEEN '2026-08-01' AND '2026-08-31'дляtimestampотрежет почти весь последний день, потому что правая граница равна полуночи 31 августа. Надёжнее полуоткрытый интервалcreated_at >= '2026-08-01' AND created_at < '2026-09-01'. Он же не даёт посчитать дважды события ровно в полночь на стыке периодов; - часовые пояса: для
timestamptzграницы читаются в часовом поясе сессии, и отчёт по Москве и по UTC разойдётся на три часа; - строки: сравнение идёт по правилам сортировки (collation).
name BETWEEN 'A' AND 'C'не включит'Cat', потому что эта строка больше'C'; NULL: не проходит ниBETWEEN, ниNOT BETWEEN. Если строки без значения нужны,OR x IS NULLпишут явно;- производительность:
BETWEENпо самой колонке использует обычный B-tree индекс как диапазон, аDATE(created_at) BETWEEN ...или функция над колонкой индекс уже не задействует.
Для числовых диапазонов вроде суммы заказа или возраста BETWEEN читается хорошо и ведёт себя предсказуемо. Для периодов времени аналитики чаще выбирают полуоткрытый интервал, и это стоит сказать вслух.
Где спотыкаются
Фильтруют месяц через BETWEEN с последним днём по колонке со временем. Выручка за последний день пропадает, и цифры не сходятся с источником.
Строят помесячную разбивку отрезками от первого числа месяца до первого числа следующего включительно. Строки ровно на границе попадают в два периода, и годовой итог получается больше реального.
Думают, что NOT BETWEEN вернёт всё остальное. Строки с NULL не попадут ни туда, ни туда, и сумма двух выборок не сойдётся с общим числом строк.