Діапазонний тип зберігає проміжок значень як одне значення: int4range, numrange, daterange, tsrange, tstzrange. Межі можуть бути включними [ чи виключними ).
SELECT tstzrange('2026-10-04 10:00', '2026-10-04 12:00', '[)');
-- оператори
period @> '2026-10-04 11:00'::timestamptz -- містить момент
period && other_period -- перетинаються
upper(period) - lower(period) -- тривалість
Найцінніше застосування - exclusion constraint. Задача: кімнату не можна забронювати двічі на час, що перетинається. Перевірка в застосунку («SELECT, чи вільно, потім INSERT») має гонку: два запити одночасно побачать «вільно».
CREATE EXTENSION IF NOT EXISTS btree_gist;
CREATE TABLE bookings (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
room_id bigint NOT NULL,
period tstzrange NOT NULL,
EXCLUDE USING gist (room_id WITH =, period WITH &&)
);
Обмеження означає: не може бути двох рядків, у яких room_id рівні і періоди перетинаються. База перевіряє це атомарно, навіть під паралельним навантаженням - друга вставка отримає помилку 23P01 (exclusion_violation).
btree_gist потрібен, щоб звичайну рівність (room_id WITH =) можна було поєднати з GiST-індексом.
Переваги діапазонів над двома колонками starts_at/ends_at:
- Перетин і вкладеність - один оператор замість чотирьох порівнянь з урахуванням меж.
- GiST-індекс прискорює пошук «що перетинається з цим проміжком».
- Exclusion constraints неможливі з двома окремими колонками без діапазону.
Ще застосування: періоди дії цін і тарифів, графіки змін, версії записів у часі («який тариф діяв 15 березня»).
Мультидіапазони (PostgreSQL 14+) - кілька непересічних діапазонів одним значенням: робочі години з перервою на обід.