Может ли таблица ссылок иметь два взаимоисключающих столбца? - PullRequest
0 голосов
/ 04 ноября 2010

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

Позвольте мне объяснить, если кто-то видит лучшее решение.

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

Конкретный пример, поскольку я не могу поделиться своим реальным случаем:

Table 'full_time_students' stores full time students
Table 'part_time_students' store part time students

Table 'class' will store class info
Table 'class_students' should store which students are in which class

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

Просто написать это почти убеждает меня пересмотреть решение за 2 столами ...

Ответы [ 3 ]

5 голосов
/ 06 ноября 2010

Переработано в ответ на комментарии.

Я не согласен ни с одним из ответов.

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

Я предполагаю две вещи:

  1. Вы думаете, что предыдущие разработчики допустили ошибку в том, что StudentFullTime и StudentPartTime должны быть объединены в Student, , потому что у них много общих столбцов

  2. У вас есть новый класс требований, который требует отношения «многие ко многим» между классом и учеником.

    • В реляционной терминологии это называется ассоциативной таблицей: в логической модели она отображается как отношение n :: n (без таблицы); в физической модели он отображается в виде таблицы. (Конечно, если у него есть столбцы, он будет отображаться в логической модели как сущность, а не как отношение.)

Хорошо, (1) неверно. Точно так же, как неправильно иметь общие столбцы, которые не были нормализованы в одну таблицу, также неправильно иметь одну таблицу с неприменимыми столбцами (столбцы, допускающие значение NULL). То, что они должны были сделать, это реализовать три таблицы ; Не один; а не два, в обычном кластере подтип-супертип.

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

    • Все мои модели данных соответствуют стандарту IDEF1X . Чтобы помочь новичкам в IDEF1X, вот документ, который объясняет Обозначение IDEF1X документ. Если вы не понимаете, что означают круги, прутья и гусиные лапки; или что означает Is на линии Отношения; или почему горизонтальная линия там, где она есть, прочитайте это сейчас.

Нормализовано до

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

Нормализовано после

Но они этого не сделали, они оставили две ненормализованные таблицы в «базе данных».

Итак, вы пришли, и вам нужно реализовать (2). При поиске «взаимоисключающих» столбцов вы обнаружили ошибку нормализации (на вашей стороне). Нужная вам ассоциативная таблица n :: n - это классы, в которых есть студенты; тот факт, что они могут быть FullTime или PartTime, вызывает беспокойство после того, как вы подтвердите основную потребность. Разумеется, после того, как вы обдумаете эту необходимость, вы должны реализовать что-то, что будет работать с обоими типами студентов.

  • если вы реализуете одну таблицу, это грубая ошибка, и вам нужны dbms, которые будут делать забавные вещи, такие как «взаимное исключение»

  • если вы реализуете две таблицы, вы просто смешиваете их ошибку. Это будет ограничено, и ваш код SQL будет уродливым.

Ошибка, исправленная вами

То, что требуется, - это чтобы вы нормализовались на вашей стороне и, следовательно, не мешали силе БД на вашей стороне.

Нормализовано Ваше

  • Одна таблица для ассоциативной таблицы и одна таблица для двух подтипов (в зависимости от наличия двух некондиционных таблиц). Простой подтип-супертип кластер 1 :: 1.

  • Нет значений Null, Полная целостность, FK, ссылочные позиции и т. Д. Простые уникальные индексы в каждой таблице. Подумайте, как будет выглядеть ваш код.

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

И, пожалуйста, перенесите существующие ключи, они вполне адекватны и уже имеют значение, не создавайте новые ключи IDENTITY.

1 голос
/ 04 ноября 2010

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

Или вы можете применить свои правила в триггере.

0 голосов
/ 04 ноября 2010

Применение бизнес-правил с использованием триггеров в MySQL уже упоминалось здесь:

Сгенерировать ошибку в триггере MySQL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...