Является ли хорошей или плохой практикой изменение дат начала в базе данных для следующего события? - PullRequest
1 голос
/ 25 марта 2012

Я пытаюсь создать календарь событий, который вначале может быть довольно большим. С этой целью, при попытках доказать это в будущем, насколько это возможно, все события, которые произошли в прошлом, будут удалены из базы данных. Однако является ли плохой практикой изменение даты начала повторяющихся событий, когда они произошли, чтобы указать, когда начнется следующее событие? Это облегчает выполнение поисковых запросов, потому что теоретически никакие события не начнутся больше, чем, скажем, неделя в прошлом, в зависимости от того, как часто обновляется база данных.

Есть ли лучший способ сделать это?

Мое текущее намерение состоит в том, чтобы иметь таблицу со списком деталей события вместе со столбцом для того, будет ли это повторение на год, месяц, неделю или день. Когда кто-то ищет события между двумя датами, я просто просматриваю каждую строку и проверяю, есть ли (EVENT START <= SEARCH FINISH && EVENT FINISH> = SEARCH START). Затем он получает все возможные события, а затем необходимо проверить повторяющиеся, чтобы увидеть, происходят ли они в течение заданного периода времени. Вот где я немного отклеился, как конкретно этого добиться. Мои мысли таковы:

Ежегодно: если СОБЫТИЕ НАЧИНАЕТСЯ + 1 ГОД <= ПОИСК ЗАКОНЧИТЬ || СОБЫТИЕ ЗАВЕРШЕНИЕ + 1 год> = НАЧАЛО ПОИСКА; повторите в течение +2 ЛЕТ и т. д., пока СОБЫТИЕ не начнется + НЕТ ГОДА> ПОИСК ЗАВЕРШИТ.

Ежемесячно: как указано выше, но + 1 месяц каждый раз.

Еженедельно: как указано выше, ЗАПУСК СОБЫТИЙ и ЗАВЕРШЕНИЕ СОБЫТИЙ будет плюс 7 ДНЕЙ МЕЖДУ РЕКУРСИЕЙ на каждую итерацию, пока СОБЫТИЕ СОБЫТИЙ + 7 ДНЕВ ПОВТОР> ПОИСК ЗАВЕРШЕН.

Ежедневно: как указано выше, НЕТ ОТЛИЧИЯ ОТ ДНЕЙ вместо 7 дней в течение недели. Это может быть использовано для указания таких вещей, как каждые 14 дней (две недели), каждые 10 дней. Даже каждую неделю можно использовать этот метод.

Однако, когда я думаю о запросе, который должен быть построен для достижения этого, я не могу не думать, что он будет очень громоздким и, вероятно, медленным. Есть ли лучший способ достичь желаемых результатов? Я до сих пор не нашел способа делать такие вещи, как это происходит в первый понедельник месяца или в последнюю пятницу месяца или во вторую субботу апреля каждого года. Возможны ли эти последние варианты?

- Изменить: добавлено ниже:

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

Я создаю веб-сайт, который позволяет организациям добавлять события, будь то разовые или повторяющиеся (ежедневно, еженедельно, ежемесячно, первый вторник месяца и т. Д.). После этого пользователь сайта сможет искать события на выбранном расстоянии (произвольно 10, 25, 50, 100 миль, вся страна) в установленную дату или между 2 указанными датами, которые могут быть на расстоянии от одного дня до с интервалом в пару лет (очевидно, что события в будущем будут минимальными или не будут существовать в зависимости от используемых дат).

В самой таблице СОБЫТИЯ в настоящее время содержится много информации о событии, такой как местоположение, стоимость, возрастная группа и т. Д. Было бы лучше иметь это в отдельной таблице, которая просматривается после того, как будет определено, является ли событие находится в пределах указанных параметров поиска? Очевидно, что не вся эта информация нужна до подробного просмотра страницы, может быть, просто имя, местоположение, стоимость и краткое описание.

Я ценю, что есть много способов снять шкуру с кошки, но я не уверен, как это сделать. Самая большая проблема, с которой я сталкиваюсь, это как структурировать мои данные так, чтобы запрос знал, находится ли рекурсия в пределах указанной даты. Кроме того, учитывая, что математика для вычисления расстояния между двумя широтами / долготами является относительно сложной, мне нужно иметь возможность встроить эти вычисления в свой запрос, иначе я все равно буду выполнять вычисления в PHP. Конечно, будет меньше результатов для обработки таким способом, но это все еще необходимо сделать.

Любые дальнейшие советы приветствуются.

Ответы [ 3 ]

3 голосов
/ 26 марта 2012

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

Один из способов сделать это - использовать такую ​​структуру -

tblEvent
--------
id
name
description
date

tblEventRecurring
-----------------
event_id
date_part
end_date

Тогда вы можете использовать такой запрос для извлечения событий -

SELECT *
FROM `tblEvent`
LEFT JOIN `tblEventRecurring`
    ON `tblEvent`.`id` = `tblEventRecurring`.`event_id`
WHERE (`tblEvent`.`date` = CURRENT_DATE AND `tblEventRecurring`.`event_id` IS NULL)
OR (
    CURRENT_DATE BETWEEN `tblEvent`.`date` AND `tblEventRecurring`.`end_date`
    AND (
        (`tblEventRecurring`.`date_part` = 'D') OR
        (`tblEventRecurring`.`date_part` = 'W' AND DAYOFWEEK(`tblEvent`.`date`) = DAYOFWEEK(CURRENT_DATE)) OR
        (`tblEventRecurring`.`date_part` = 'M' AND DAYOFMONTH(`tblEvent`.`date`) = DAYOFMONTH(CURRENT_DATE))
    )
)

ОБНОВЛЕНИЕ Добавлен следующий пример возврата событий для заданного диапазона дат.

При возврате дат для заданного диапазона дат вы можете присоединить вышеуказанный запрос к таблице, представляющей диапазон дат -

SET @start_date = '2012-03-26';
SET @end_date = '2012-04-01';

SELECT *
FROM (
    SELECT @start_date + INTERVAL num DAY AS `date`
    FROM dummy
    WHERE num < (DATEDIFF(@end_date, @start_date) + 1)
) AS `date_list`
INNER JOIN (
    SELECT `tblEvent`.`id`, `tblEvent`.`date`, `tblEvent`.`name`, `tblEventRecurring`.`date_part`, `tblEventRecurring`.`end_date`
    FROM `tblEvent`
    LEFT JOIN `tblEventRecurring`
        ON `tblEvent`.`id` = `tblEventRecurring`.`event_id`
    WHERE `tblEvent`.`date` BETWEEN @start_date AND @end_date
    OR (`tblEvent`.`date` < @end_date AND `tblEventRecurring`.`end_date` > @start_date)
) AS `events`
    ON `events`.`date` = `date_list`.`date`
    OR (
        `date_list`.`date` BETWEEN `events`.`date` AND `events`.`end_date`
        AND (
            (`events`.`date_part` = 'D') OR
            (`events`.`date_part` = 'W' AND DAYOFWEEK(`events`.`date`) = DAYOFWEEK(`date_list`.`date`)) OR
            (`events`.`date_part` = 'M' AND DAYOFMONTH(`events`.`date`) = DAYOFMONTH(`date_list`.`date`))
        )
    )
WHERE `date_list`.`date` BETWEEN @start_date AND @end_date
ORDER BY `date_list`.`date`;

При желании вы можете заменить переменные SQL на переменные PHP. Для отображения дней без каких-либо событий вы можете изменить INNER JOIN между двумя производными таблицами date_list и events на LEFT JOIN.

Таблица dummy состоит из одного столбца с номерами от 0 до того, что вам нужно. В этом примере создается фиктивная таблица с достаточным количеством данных для покрытия за один месяц. Вы можете легко заполнить его, используя INSERT... SELECT... на AI PK другой таблицы -

CREATE TABLE `dummy` (
    `num` SMALLINT UNSIGNED NOT NULL PRIMARY KEY
);
INSERT INTO `dummy` VALUES
    (00), (01), (02), (03), (04), (05), (06), (07), (08), (09),
    (10), (11), (12), (13), (14), (15), (16), (17), (18), (19),
    (20), (21), (22), (23), (24), (25), (26), (27), (28), (29),
    (30), (31);
1 голос
/ 25 марта 2012

Разбейте его Иметь одну таблицу для вентиляций, которые еще не произошли, с повторяющимся идентификатором события.Таким образом, вы можете просто ткнуть туда один раз с повторяющимся идентификатором сброса нуля.Избавьтесь / заархивируйте прошлые и т. Д.

Иметь другой для данных о повторяющихся событиях.

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

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

Если вы хотите получить от этого будущие задания.то есть все, что нужно сделать в следующем месяце.

Это будет запрос объединения.Один, чтобы получить все «текущие задания», объединенный с одним, чтобы получить все задания, которые будут повторяться в следующем месяце.

Не могу не подчеркнуть этого достаточно, получить правильный дизайн данных, код «просто происходит»,Если ваши данные испорчены, как в одном поле «дата начала», служащем двум различным потребностям, то каждый раз, когда вы приближаетесь к нему, вам приходится иметь дело с этим двойным использованием.Забудьте об этом один раз, и вы получите что-нибудь от мучительного беспорядка до катастрофы.

Добавление столбца Recurring_Start_Date было бы лучше, чем ваш текущий план, не так ли.Вы не будете задавать этот вопрос, потому что ваши данные будут соответствовать вашим потребностям.

0 голосов
/ 26 марта 2012

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

Это также немного облегчит такие вещи, как «Третий четверг каждого месяца». Если вы попытаетесь выполнить какие-либо вычисления в запросе, это будет сложно и, вероятно, медленно.

...