Как разработать схему для периодов дат с исключениями?

#database #database-design #calendar

#База данных #база данных-дизайн #Календарь

Вопрос:

Сайт посвящен специальным событиям со скидками. Каждое событие содержит период времени (точнее, даты), в течение которого оно является действительным. Однако часто возникает ограничение, заключающееся в том, что сделка недействительна, скажем, по субботам и воскресеньям (или даже в определенный день).

В настоящее время мой грубый дизайн состоял бы в том, чтобы иметь две таблицы:

В таблице событий хранятся идентификатор события, дата начала и окончания продолжительности и все другие вещи.

В таблице EventInvalidDate хранится идентификатор события и конкретные даты, по которым сделки недействительны. Для этого требуется, чтобы код приложения заранее вычислял недопустимые даты.

Кто-нибудь знает лучший шаблон, соответствующий этому требованию, или возможную ошибку для моего дизайна? Это требование похоже на подмножество общей модели календаря, поскольку оно не требует бесконечного повторения событий в будущем (т. Е. Каждое событие имеет определенную продолжительность).

Обновить

Мой коллега предложил создать таблицу периодов с датами начала и окончания. Если период находится между 1 января и 7 января, при этом 3 января является исключением, в таблице будет записано: 1 января ~ 2 января, 4 января ~ 7 января.

Кто-нибудь знает, лучше ли это так же, как подход ответа, с точки зрения производительности SQL. Спасибо

Ответ №1:

Указание того, какие даты не включены, может уменьшить количество строк базы данных, но это усложняет вычисления, запросы и отчеты.

Я бы перевернул ее с ног на голову.

  • Есть главная Event таблица, в которой перечислены первая и последняя дата события.

  • Также есть подробная EventDates таблица, которая заполняется всеми датами, когда доступно событие.

Использование этого подхода упрощает работу, особенно при написании запросов и отчетов.

Обновить

Наличие строки на дату позволяет выполнять точные соединения по датам с другими таблицами и позволяет агрегировать данные за день для целей отчетности.

 select ...
from sales
     inner join eventDates
     on sales.saleDate = eventDates.date
  

Если в вашей таблице EventDates используются даты начала и окончания, создавать соединения становится сложнее:

 select ...
from sales
     inner join eventDates
     on sales.saleDate >= eventDates.start and sales.SaleDate < eventDates.finish
  

Соединения с точным совпадением определенно выполняются по индексу, если таковые имеются, в каждой RDBMS, которую я проверил; диапазон совпадает, как и во втором примере, я не уверен. Вероятно, с точки зрения производительности с ними все в порядке, если только в итоге вы не получите метрическую тонну данных.