Составная таблица ссылок на внешние ключи
-
06-07-2019 - |
Вопрос
У меня есть структура таблицы, я не совсем уверен, как создать лучший способ.
В основном у меня есть две таблицы: tblSystemItems и tblClientItems. У меня есть третья таблица, в которой есть столбец, который ссылается на «Элемент». Проблема в том, что этот столбец должен ссылаться либо на системный элемент, либо на элемент клиента - не имеет значения, какой именно. Системные элементы имеют ключи в диапазоне 1..2 ^ 31, в то время как клиентские элементы имеют ключи в диапазоне -1 ..- 2 ^ 31, поэтому столкновения никогда не будет.
Всякий раз, когда я запрашиваю элементы, я делаю это через представление, которое делает UNION ALL между содержимым двух таблиц.
Таким образом, оптимально, я бы хотел, чтобы внешний ключ ссылался на результат представления, так как представление всегда будет объединением двух таблиц, сохраняя при этом идентификаторы уникальными. Но я не могу этого сделать, так как не могу сослаться на представление.
Теперь я могу просто сбросить внешний ключ, и все хорошо. Тем не менее, я действительно хотел бы иметь некоторые функции проверки ссылок и каскадного удаления / установки нуля. Есть ли способ сделать это, кроме триггеров?
Решение
извините за поздний ответ, меня поразил серьезный случай уикенда.
Что касается использования третьей таблицы для включения PK из клиентских и системных таблиц - мне это не нравится, поскольку это слишком усложняет синхронизацию и все еще требует, чтобы мое приложение знало третью таблицу.
Другая проблема, которая возникла, заключается в том, что у меня есть третья таблица, которая должна ссылаться на элемент - системный или клиентский, это не имеет значения. Разделение таблиц в основном означает, что мне нужно иметь два столбца, ClientItemID и SystemItemID, каждый из которых имеет ограничение для каждой из своих таблиц с обнуляемостью - довольно некрасиво.
В итоге я выбрал другое решение. Вся проблема заключалась в том, чтобы легко синхронизировать новые системные элементы в таблицах, не связываясь с клиентскими элементами, избегая коллизий и т. Д.
В итоге я создал только одну таблицу Items. У элементов есть битовый столбец с именем " SystemItem " это определяет, ну, очевидно, В моей базе данных разработки / системы у меня есть PK как int int (1,1). После того, как таблица была создана в клиентской базе данных, ключ идентификации изменяется на (-1, -1). Это означает, что элементы клиента идут в отрицательном направлении, а элементы системы - в положительном.
Для синхронизации я в основном игнорирую что-либо с (SystemItem = 1), синхронизируя остальное, используя IDENTITY INSERT ON. Таким образом, я могу синхронизироваться, полностью игнорируя элементы клиента и избегая коллизий. Я также могу ссылаться только на один " Предметы " таблица, которая охватывает как клиентские, так и системные элементы. Единственное, что нужно иметь в виду, это исправить стандартный кластеризованный ключ, чтобы он убирался, чтобы избежать всех видов реструктуризации страницы, когда клиент вставляет новые элементы (обновления клиента по сравнению с обновлениями системы, как 99% / 1%).
Другие советы
Вы можете создать уникальный идентификатор (сгенерированный в db - sequence, autoinc и т. д.) для таблицы, которая ссылается на элементы, и создать два дополнительных столбца ( tblSystemItemsFK и tblClientItemsFk ) где вы ссылаетесь на системные элементы и клиентские элементы соответственно - некоторые базы данных позволяют вам иметь внешний ключ nullable .
Если вы используете ORM, вы даже можете легко различать элементы клиента и элементы системы (таким образом, вам не нужно использовать отрицательные идентификаторы для предотвращения совпадения идентификаторов), основываясь только на информации о столбцах.
С немного большим количеством bakcground / context, вероятно, легче определить оптимальное решение.
Возможно, вам нужна таблица, скажем, tblItems, в которой просто хранятся все первичные ключи двух таблиц. Для вставки элементов потребуется два шага, чтобы при вводе элемента в таблицу tblSystemItems PK вводился в таблицу tblItems.
В третьей таблице есть FK to tblItems. В некотором смысле tblItems является родителем двух других таблиц элементов. Для запроса элемента необходимо создать JOIN между tblItems, tblSystemItems и tblClientItems.
[РЕДАКТИРОВАТЬ - для комментариев ниже] Если tblSystemItems и tblClientItems контролируют свои собственные PK, то вы все равно можете их разрешить. Возможно, вы сначала вставите в tblSystemItems, а затем вставите в tblItems. Когда вы реализуете структуру наследования с помощью такого инструмента, как Hibernate, вы в итоге получаете что-то вроде этого.
Добавьте таблицу с именем Items с PK ItemiD и один столбец с именем ItemType = " System " или "Клиент" затем таблица PK ClientItems (с именем ClientItemId) и PK SystemItems (с именем SystemItemId) также будут FKs для Items.ItemId, (Эти отношения являются отношениями от нуля до одного (0-1)
Затем в вашей третьей таблице, которая ссылается на элемент, просто поместите ограничение FK на элемент itemId в этой дополнительной таблице (Items) ...
Если вы используете хранимые процедуры для реализации вставок, просто сохраните процедуру, которая вставляет элементы, сначала вставьте новую запись в таблицу «Элементы», а затем, используя автоматически сгенерированное значение PK в этой таблице, вставьте фактическую запись данных в либо SystemItems, либо ClientItems (в зависимости от того, какой он есть) как часть одного и того же хранимого вызова proc, используя автоматически сгенерированное (идентификационное) значение, которое система вставила в столбец ItemId таблицы Items. Р>
Это называется "SubClassing"
Я ломал голову над дизайном твоего стола. Я не уверен, что это правильно. Я понимаю, что третья таблица может просто предоставлять детальную информацию, но я не могу не думать, что первичный ключ на самом деле тот, который находится в вашей таблице ITEM, а ключи FOREIGN - те, которые находятся в вашей системе и таблицах элементов клиента. Тогда вам просто нужно будет выполнить правильные внешние соединения из Item в системные и клиентские таблицы элементов, и все ограничения будут работать нормально.
У меня похожая ситуация в базе данных, которую я использую. У меня есть «ключ-кандидат» на каждой таблице, которую я называю EntityID. Затем, если есть таблица, которая должна ссылаться на элементы более чем в одной из других таблиц, я использую EntityID для ссылки на эту строку. У меня есть таблица Entity для перекрестной ссылки на все (так что EntityID является первичным ключом таблицы Entity, а все остальные EntityID являются FK), но я не часто использую таблицу Entity.