Обмеження унікальності з діапазоном дат


15

Розглянемо pricesтаблицю з цими стовпцями:

id         integer primary key
product_id integer -- foreign key
start_date date not null
end_date   date not null
quantity   integer
price      numeric

Я хотів би, щоб база даних застосувала правило про те, що продукт може мати лише одну ціну за певну кількість у діапазоні дат (через where <date> BETWEEN start_date AND end_date).

Чи можливе таке обмеження на основі діапазону?

Відповіді:


23

Так, ви можете використовувати EXCLUDEобмеження, яке є узагальненням UNIQUEобмежень:

ALTER TABLE prices 
  ADD CONSTRAINT unique_price_per_product_quantity_daterange
    EXCLUDE  USING gist
    ( product_id WITH =, 
      quantity WITH =, 
      daterange(start_date, end_date, '[]') WITH &&   -- this is the crucial
    );

Обмеження можна інтерпретувати як таке:

Не допускайте двох рядків, які мають однакові product_id, однакові quantityта перекриваються &&діапазони дат ( ).

Значення '[]'призначений для потрібного діапазону дат, що включає все включено (за замовчуванням - [)для типів діапазону).

Дивіться документацію щодо обмежень для типів діапазону . Можливо, вам також потрібно буде додати розширення, запустивши (один раз для кожної бази даних, де ви хочете встановити це):

CREATE EXTENSION btree_gist;

Це круто. Я не думаю, що daterangeце саме так, оскільки це ексклюзивна нижня межа, але це легко виправити. Чи слід реально мігрувати свої дані, щоб використовувати daterangeтип стовпця (можна зробити це окремим питанням, якщо це краще) або це розумне питання щодо двох стовпців?
шип

За замовчуванням включно нижня межа та виключна верхня межа, якщо я добре пам’ятаю. Я редагую все включно. Зазвичай я віддаю перевагу за замовчуванням, оскільки це звичайно в готельних програмах. (Я заходжу в готель о 2-й, виходжу о 8-й, пробув 6 днів. Наступний окупант може прийти о 8-й)
ypercubeᵀᴹ

Я можу насправді перевернути, на якому саме ... щойно дізнався про типи діапазону сьогодні, і я читаю документи!
шип

Я не впевнений у тому, що є кращим, 2 стовпчики або один із датним діапазоном. Можна задати окреме запитання. Це, мабуть, залежатиме від потрібного вам використання, запитів, простоти використання (та потреби в індексах). Якщо є окремі стовпці, простіше, наприклад, мати індекс на (product_id, start_date). З діапазоном дат це повинно бути індексом(product_id, lower(range_column))
ypercubeᵀᴹ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.