Противоречивые желания в дизайне баз данных с полями двух одинаковых функций

StackOverflow https://stackoverflow.com/questions/112780

Вопрос

Хорошо, сейчас я делаю таблицу «Предметы коробки».

Теперь предмет в коробке, в зависимости от того, для чего он используется/статуса предмета, может оказаться связанным с ящиком «Доставка» или ящиком «Возврат».

Предмет коробки может быть дефектным: если это так, в строке предмета коробки будет установлен флаг (IsDefective), и предмет коробки будет помещен в ящик «Возврат» (а другие предметы будут возвращены этому продавцу).В противном случае предмет коробки в конечном итоге будет помещен в коробку «Доставка» (вместе с другими предметами, подлежащими отправке).(Обратите внимание, что в полях «Доставка» и «Возврат» есть свои таблицы:нет одного общего стола для всех ящиков...хотя, возможно, мне следует рассмотреть возможность сделать это, если это возможно, в качестве третьей возможности?)

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

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

BoxItemid Описание ISEDEFECTIVE SHIPPINGBOXID RETURNBOXID и т. Д.

Это прояснило бы отношения, но это кажется расточительным (поскольку в любой момент времени будет использоваться только одно из отношений).Тогда я подумал, что могу иметь только одно поле для BoxID и определять, к какому BoxID оно относится (идентификатор ящика для доставки или ящика для возврата), на основе поля IsDefective:

BoxiTemid Описание ISEDECECTIOVE BOXID и т. Д.

Это кажется менее расточительным, но меня это не устраивает.Связь не очевидна.

Итак, я предлагаю это вам, гуру баз данных Stackoverflow.Что бы вы сделали в такой ситуации?

РЕДАКТИРОВАТЬ:Спасибо всем за ваш вклад!Это заставило меня о многом задуматься.Во-первых, я собираюсь использовать ORM в следующий раз, когда начну такой проект.=) На двоих, так как меня сейчас нет, то я откушу четыре байта и задействую два поля.

Спасибо всем еще раз!

Это было полезно?

Решение

Я за Psychotic Venom и Мэттланта.

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

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

«Преждевременная оптимизация — корень всех зол» и все такое.Хотя это кажется расточительным, помните, что вы храните.Поскольку это идентификаторы, они, вероятно, просто целые числа, возможно, 4 байта.Потратить четыре байта на запись — это, по сути, пустяки.Фактически, из-за заполнения для размещения вещей по четным адресам или других подобных вещей может быть «бесплатно» поместить туда это дополнительное поле.Все зависит от конструкции БД.

Если у вас нет очень веской причины пойти по полиморфному пути (например, вы используете встроенную систему с небольшим объемом памяти или вам приходится выполнять репликацию по какому-то очень медленному каналу со скоростью 9600 бит/с), это, вероятно, не будет стоить головной боли, с которой вы можете столкнуться. .Необходимость прописывать все эти особые случаи в ваших запросах может раздражать.

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

Другие советы

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

Я бы использовал то, что вызывает Hibernate Таблица на подкласс, поэтому моя БД будет содержать 3 таблицы для ящиков: Box, ShippingBox, и ReturnBox.ФК в BoxItem указал бы на Box.

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

Как насчет этого?

BoxItem:
BoxItemID, Description, IsDefective

Box:
BoxID, Description

BoxItemMap:
BoxID, BoxItemID, BoxItemType

Тогда вы можете указать BoxItemType в виде перечисления или целого числа, где вы определяете константы в своем приложении как «Возврат» или «Доставка» в качестве типа коробки.

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

По сути, у вас есть базовая таблица под названием box.Затем у вас есть еще два стола: коробка для доставки и коробка для возврата.Эти двое добавляют любые дополнительные поля, которые являются для них особенными.они связаны с ящиком с соотношением 1:1. Базовая таблица Boz имеет общие поля для всех типов ящиков.

Вы связываете BoxItem с таблицей блоков.Чтобы получить правильный тип ящика, выполните запрос, который объединяет дочерний ящик с корневым ящиком на основе ключа.Запись, которая есть как в базовом, так и в дочернем ящике, относится к этому типу.

Вам просто нужно быть осторожным, как уже упоминалось, когда вы создаете тип поля, чтобы все было сделано правильно.НО именно для этого и нужно тестирование.Код для их добавления нужно писать только один раз.Или используйте ORM.

Почти все ORM поддерживают эту стратегию.

Я бы использовал только одну таблицу BoxItems с IsDefective, ShippingBoxID, полями, связанными с коробкой доставки, ReturnBoxID и полями, связанными с коробкой возврата.Некоторые поля всегда будут иметь значение NULL для каждой записи.

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

Я бы, наверное, пошел с:

BoxTable:
box_id, box_descrip, box_status_id ...
     1, Lovely Box, 1
     2, Borked box, 2
     3, Ugly Box, 3
     4, Flammable Box, 4

       BoxStatus:
       box_status_id, box_status_name, box_type_id, ....
                   1,Shippable, 1
                   2,Return, 2
                   3,Ugly, 2
                   4,Dangerous,3

                BoxType:
                box_type_id, box_type_name, ...
                          1, Shipping box, ...
                          2, Return box, ....
                          3, Hazmat box, ...

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top