Я бы сделал это в два шага:
- Преобразуйте повторяющиеся записи в два значения DATETIME на следующие две недели.Это будет один подзапрос.
- Собрать неповторяющиеся записи за тот же период.Это будет второй подзапрос.
СОЮЗ двух подзапросов дает вам все события с их фактической датой и временем возникновения;упорядочить это правильно тривиально.
Если вам необходимо записать, является ли информация повторяющейся встречей, сохраните что-то (возможно, просто 'R' или 'N') в списке выборадва подзапроса, чтобы вы могли определить, была ли исходная запись повторяющейся или неповторяющейся.
Я не эксперт в манипулировании MySQL DATETIME - но я знаю, что меня нет в этой областидругая СУБД, а именно Informix.Для моих целей в этой дискуссии в таблице есть только два интересных столбца: date_time
и weekly_day
.Я предполагаю, что вы используете соглашение MySQL, что 1 = воскресенье, 7 = суббота.Поскольку нам требуется информация за 2 недели для повторяющихся событий, вероятно, проще всего сгенерировать 3 недели и отфильтровать несущественные.
С учетом контрольной даты и целого дня недели мы можем получитьтри значения из него с использованием:
refdate - DAYOFWEEK(refdate) + day_of_week
refdate - DAYOFWEEK(refdate) + day_of_week + INTERVAL 7 DAYS
refdate - DAYOFWEEK(refdate) + day_of_week + INTERVAL 14 DAYS
Эти дают три даты;первый может быть в прошлом или третий может быть слишком далеко в будущем (и, следовательно, нужно отказаться).Это арифметика, когда даты - это количество дней с контрольной даты (как в Informix).Чтобы перевести третью строку в MySQL, предполагая, что 'refdate' равен NOW()
, нам, кажется, нужно написать (необычно многословно - я думал, что Informix был очень многословен для манипуляции DATETIME):
DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())), INTERVAL weekly_day DAY),
INTERVAL 14 DAY)
Здесь яЯ предполагаю, что я могу привести целое число в weekly_day
к числу дней;отрегулируйте при необходимости.Эти формулы дают три значения DATE для каждой из повторяющихся записей, из которых два являются релевантными.Чтобы добавить время, я думаю, нам нужно:
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())), INTERVAL weekly_day DAY),
INTERVAL 14 DAY), INTERVAL TIME(date_time) HOUR_SECOND)
Итак, первый подзапрос, упомянутый в моем первоначальном ответе, должен быть трехсторонним СОЮЗОМ.
SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL 14 DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL 7 DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events;
Теперь вам нужно отфильтровать это в течение «следующих двух недель».Какой диапазон даты / времени это точно?От эталонного момента - назначенный NOW ()?Или с начала справочного дня?Или с начала дня после контрольного дня?Все может быть правдоподобным;поскольку код, по-видимому, использует эталонный режим (и он самый простой), мы пойдем с этим:
SELECT *
FROM (SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL 14 DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL 7 DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events) AS r
WHERE r.event_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 14 DAY);
Это дает повторяющиеся события.Состояние фильтра на r.event_time
может быть перенесено (реплицировано) в каждую ветвь UNION, но я оставлю его там, где оно есть, временно.
Неповторяющиеся события находят с помощью:
SELECT 'N' AS info_mode,
date_time AS event_time
FROM events AS e
WHERE e.date_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 14 DAY)
AND DATE(e.date_time) != DATE '0000-00-00';
Следовательно, мы можем создать объединение этих двух запросов.Можно перетащить условие на event_time
из двух подзапросов (и мы можем надеяться, что оптимизатор затем «вернет его»).И подзапрос непериодических событий просто становится четвертой частью UNION, что приводит к:
SELECT *
FROM (SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL 14 DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL 7 DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT 'R' AS info_mode,
DATE_ADD(DATE_ADD(DATE_SUB(NOW(), DAYOFWEEK(NOW())),
INTERVAL weekly_day DAY),
INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT 'N' AS info_mode,
date_time AS event_time
FROM events
WHERE DATE(e.date_time) != DATE '0000-00-00'
) AS e
WHERE e.event_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 14 DAY);
Итак, это должно дать вам список типов событий (повторяющихся, неповторяющихся) ите, которые происходят в ближайшие 14 дней.Вам просто нужно добавить обратно столбцы id
, name
и info
(плюс, для отладки, необработанные столбцы date_time
и weekly_day
) к каждому из 4 запросов в UNION и ORDER BYe.event_time
(и любые столбцы разрыва связей, которые вы хотите добавить).
Пожалуйста, будьте любезны с синтаксическими или специфическими для СУБД семантическими ошибками;Я надеюсь, что концепция ясна (и правильна), даже если есть детали, которые не верны из-за незнания деталей MySQL.