Подтвердить что ты не робот

Каков наилучший способ хранения дней недели, когда событие происходит в реляционной базе данных?

Мы пишем продукт для управления записями для школ, и одним из требований является способность управлять расписаниями курсов. Я не смотрел код, как мы справляемся с этим (сейчас я нахожусь в другом проекте), но тем не менее я начал задаваться вопросом, как лучше всего справиться с одной частью этого требования, а именно, как справиться с тем, что каждый курс может проводиться один или несколько дней недели и как лучше всего хранить эту информацию в базе данных. Чтобы обеспечить некоторый контекст, таблица bare-bones Course может содержать следующие столбцы:

Course          Example Data
------          ------------

DeptPrefix      ;MATH, ENG, CS, ...
Number          ;101, 300, 450, ...
Title           ;Algebra, Shakespeare, Advanced Data Structures, ...
Description     ;...
DaysOfWeek      ;Monday, Tuesday-Thursday, ...
StartTime       
EndTime           

Что мне интересно, каков наилучший способ обработки столбца DaysOfWeek в этом (надуманном) примере? Проблема, с которой я сталкиваюсь, заключается в том, что это многозначное поле: то есть вы можете иметь курс в любой день недели, и один и тот же курс может проводиться более одного дня. Я знаю, что определенные базы данных изначально поддерживают многозначные столбцы, но есть ли "лучшая практика" для этого, предполагая, что база данных не поддерживает ее?

Я до сих пор предлагал следующие возможные решения, но мне интересно, есть ли у кого-нибудь лучшее:

Возможное решение №1: Обработать DaysOfWeek как поле бит

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

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

Минусы: сложнее писать запросы, которые используют столбец DaysOfWeek (хотя вы можете справиться с этим на уровне приложения или создать представления и хранимые процедуры в базе данных, чтобы упростить это), breaks реляционной базы данных.

Возможное решение # 2: сохранить DaysOfWeek в виде строки символов

Это по существу тот же подход, что и использование битового поля, но вместо обращения к необработанным битам вы назначаете уникальное письмо для каждого дня недели, а столбец DaysOfWeek просто хранит последовательность букв, указывающую, какие дни курс проводится. Например, вы можете связать каждый день недели с одним символьным кодом следующим образом:

Weekday      Letter
-------      ------

Sunday       S
Monday       M
Tuesday      T
Wednesday    W
Thursday     R
Friday       F
Saturday     U

В этом случае курс, проводимый в понедельник, вторник и пятницу, будет иметь значение 'MTF' для DaysOfWeek, а класс, который будет проводиться только по средам, будет иметь значение DaysOfWeek 'W'.

Преимущества: проще справиться с запросами (т.е. вы можете использовать INSTR или его эквивалент, чтобы определить, удерживается ли класс в данный день). Работает с любой базой данных, которая поддерживает INSTR или эквивалентную функцию (большинство, я бы предположил...). Также более дружелюбно смотреть и легко видеть, что происходит в запросах, которые используют столбец DaysOfWeek.

Против. Единственный реальный "кон" - это то, что, подобно подходу битового поля, это разбивает реляционную модель, сохраняя переменное число значений в одном поле.

Возможное решение №3: используйте таблицу поиска (уродливый)

Еще одна возможность - создать новую таблицу, в которой хранятся все уникальные комбинации дней недели, и столбец Course.DaysOfWeek просто будет внешним ключом в этой таблице поиска. Тем не менее, это решение кажется самым неэлегантным, и я только рассматривал его, потому что это делалось так, как это делалось в Relational Way TM.

Преимущества: это единственное решение, которое является "чистым" с точки зрения реляционной базы данных.

Против: он неэлегантный и громоздкий. Например, как бы вы создали пользовательский интерфейс для назначения соответствующих будних дней данному курсу вокруг таблицы поиска? Я сомневаюсь, что пользователь хочет иметь дело с выборами по строкам "воскресенье", "воскресенье, понедельник", "воскресенье, понедельник, вторник", "воскресенье, понедельник, вторник, среда" и т.д....

Другие идеи?

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

4b9b3361

Ответ 1

Я бы избегал строковой опции для чувства чистоты: она добавляет дополнительный уровень кодирования/декодирования, который вам не нужен. Это может также испортить вас в случае интернационализации.

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

Я бы избежал поиска, потому что это было бы слишком нормальным. Если ваш набор элементов поиска не является очевидным или, возможно, может измениться, он будет излишним. В случае дней недели (в отличие от США, например), я бы спокойно спал с фиксированным набором.

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

Наконец, слово предупреждения о домене: многие школы делают странные вещи со своими графиками, где они "меняют дни", чтобы сбалансировать равное количество будних дней каждого типа в течение семестра, несмотря на праздники. Я не совсем понимаю вашу систему, но, пожалуй, наилучшим подходом было бы сохранить таблицу фактических дат, в которых предполагается, что курс будет проходить. Таким образом, если есть два вторника в неделю, учителю можно заплатить за то, что он дважды появился, а учитель в четверг, который был отменен, не заплатит.

Ответ 2

Мне не сложно записывать запросы, если мы используем бит. Просто используйте простую двоичную математику. Я думаю, что это самый эффективный метод. Лично я делаю это все время. Посмотрите:

 sun=1, mon=2, tue=4, wed=8, thu=16, fri=32, sat=64. 

Теперь, скажем, курс проводится в понедельник, в среду и в пятницу. значение для сохранения в базе данных будет 42 (2 + 8 + 32). Затем вы можете выбрать курсы в следующую среду:

select * from courses where (days & 8) > 0

Если вы хотите, чтобы курсы на thu и fri вы писали:

select * from courses where (days & 48) > 0

Эта статья актуальна: http://en.wikipedia.org/wiki/Bitwise_operation

вы можете поместить числа дней недели, как константы в свой код, и это будет достаточно ясно.

Надеюсь, что это поможет.

Ответ 3

Возможное # 4: Почему это должен быть один столбец? Вы можете добавить 7 бит столбцов для каждого дня недели в таблицу. Написание SQL против него просто, просто проверьте для 1 в столбце по вашему выбору. И чтение кода приложения из базы данных просто скрывает это в коммутаторе. Я понимаю, что это ненормальная форма, и я обычно трачу довольно много времени, пытаясь отменить такие проекты у предыдущих программистов, но я несколько сомневаюсь, что мы собираемся добавить восьмой день на неделю в ближайшее время.

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

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

Изменить: я должен добавить, что # 3 и вышеприведенное предложение легче добавить индексы. Я не уверен, как можно написать SQL-запрос, например "получить все классы в четверг" для запросов №1 или №2, которые не приведут к сканированию таблицы. Но сегодня я могу быть тусклым.

Ответ 4

Решение № 3, по-видимому, ближе всего к тому, что я бы рекомендовал. Расширение идеи таблицы поиска. Каждый курс имеет одну или несколько сеансов. Создайте таблицу сеанса с атрибутами: course_id, day, time, lecturer_id, room_id и т.д.

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

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

Значение таблиц будет более четким, что упростит долгосрочное обслуживание.

Ответ 5

Если вы выберете один или два, ваша таблица не будет в 1NF (первая нормальная форма), так как она содержит многозначный столбец.

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

Ответ 6

Если производительность является проблемой, я бы рекомендовал более чистую разметку # 3.

Свяжите свой курс с таблицей "расписание".

Это, в свою очередь, связано с таблицей days_in_schedule.

В таблице days_in_schedule указаны столбцы имя_расписания и дата in_schedule_day. Строка для каждого действительного дня в этом расписании.

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

Вы можете справиться не только с курсом только по пятницам, но также "только в первом семестре", "лаборатория закрыта для ремонта в третьем семестре", а "канадский филиал имеет календарь расписания знакомств".

Другие возможные запросы: "Какая дата окончания 20-дневного курса, начинающегося 1 апреля", который "расписывает больше всего". Если вы действительно хорошо разбираетесь в SQL, вы можете спросить: "Какие возможные дни открыты в курсе xxx для ученика, который уже забронирован для курса yyy", - что у меня такое чувство, это настоящий кукол вашей предлагаемой системы.