Если у вас есть таблица RENTAL (в реальной версии потребуется много других деталей):
CREATE TABLE Rental
(
start DATE NOT NULL,
end DATE NOT NULL
);
и вы заполните его:
INSERT INTO rental VALUES('2011-08-20', '2011-09-05');
INSERT INTO rental VALUES('2011-08-20', '2011-08-25');
тогда этот запрос дает правдоподобный результат:
SELECT r.start AS r_start, r.end AS r_end,
s.start AS s_start, s.end AS s_end,
GREATEST(r.start, s.start) AS p_start,
LEAST(r.end, s.end) AS p_end,
DATEDIFF(LEAST(r.end, s.end), GREATEST(r.start, s.start)) + 1 AS days,
s.id, s.slug
FROM rental AS r
JOIN season_dates AS s ON r.start <= s.end AND r.end >= s.start;
Это дает:
r_start r_end s_start s_end p_start p_end days id slug
2011-08-20 2011-09-05 2011-07-01 2011-08-31 2011-08-20 2011-08-31 12 3 high
2011-08-20 2011-09-05 2011-09-01 2011-10-31 2011-09-01 2011-09-05 5 4 mid
2011-08-20 2011-08-25 2011-07-01 2011-08-31 2011-08-20 2011-08-25 6 3 high
Обратите внимание, что я считаю 12 дней вместо 11; это +1
в выражении days
. Это становится сложно; Вы должны решить, будет ли автомобиль возвращен в тот же день, когда он был взят в аренду, будет ли это один день аренды? Что если он будет возвращен на следующий день? Может быть, время имеет значение? Но это входит в подробные бизнес-правила, а не в общие принципы. Может быть, продолжительность больше из необработанных DATEDIFF () и 1? Также обратите внимание, что в этой схеме указаны только даты начала и окончания аренды; реальная схема будет иметь какой-то номер договора аренды в таблице аренды.
(Исповедь: смоделирован с использованием IBM Informix 11.70.FC2 на MacOS X 10.7.1, но MySQL задокументирован как поддерживающий LEAST, GREATEST и DATEDIFF, и я смоделировал их в Informix. Наиболее заметное отличие может заключаться в том, что Informix имеет DATE введите без какого-либо компонента времени, поэтому время не требуется и не отображается.)
Но [...] период сезонов всегда один и тот же каждый год. Поэтому я подумал сравнить только дни и месяцы. 2011 год не важен. В последующие годы будет использоваться только 2011 год. На этот раз проблема возникает. Например, низкий сезон включает в себя ноябрь, декабрь и затем переход на январь, февраль, март, апрель. Если пользователь выбирает диапазон дат с 01.05.2011 по ... 2011 Нет проблем. Я просто сравниваю месяц и день с DATE_FORMAT (конец, «% m /% d»). Но если он выберет диапазон с декабря по январь следующего года, как мне рассчитать дни?
Обратите внимание, что 5 записей в год в таблице Season_Dates не приведут к потере 8 "гибкого диска из-за емкости хранилища в течение хороших нескольких лет, не говоря уже о монстрах с диском 500 ГиБ. Так что, безусловно, самая простая вещь определить записи на 2012 год в 5 новых строках таблицы Season_Dates. Это также позволяет обрабатывать тот факт, что в декабре власти, принимающие решения, примут правила, которые будут другими (с 20 декабря по 4 января будет «середина»). например, не «низкий» сезон).