Я разрабатываю базу данных для нашей команды по продажам, чтобы использовать ее в качестве инструмента быстрого поиска работы. Я хотел бы получить некоторые отзывы о конкретном аспекте дизайна.
Цитата в основном создается путем выбора списка предварительно определенных «сборок», каждая из которых имеет согласованную цену. Упрощенный вид основной формы выглядит так:
+------------ --- ---+
| Assembly options |
+------------+------------+----------+------------+---+---+---+ --- +--+
| assembly ▼ | unit cost | quantity | total cost | 1 | 2 | 3 | |50|
+------------+------------+----------+------------+---+---+---+ --- +--+
| VSD55 | £10'000 | 2 | £25'500 | 1 | 1 | | | |
| RDOL2.2 | £2'000 | 1 | £1'500 | | 1 | | | |
| DOL5.0 | £1'000 | 1 | £1'200 | | | 1 | | |
+------------+------------+----------+------------+---+---+---+ --- +--+
Пользователь выбирает предопределенную сборку, вводит количество и выбирает любые требуемые «опции». Каждая сборка потенциально имеет до 50 доступных опций. Опция также является предопределенной сборкой (сборкой) с собственной ценой. «Общая стоимость» для каждой строки рассчитывается как (основная стоимость сборки * количество) + стоимость любых опций.
Когда пользователь перемещает курсор в поле опций, имя и цена этого опциона становятся ему известными.
Теперь это где это становится сложным. Каждая сборка имеет свой список доступных опций. т. е. опция 1 для VSD55 представляет собой сборку, отличную от опции 1 для DOL5.0.
Что касается сборок, то здесь приведены упрощенные таблицы, которые я использую:
+-----------------+ +------------------------+ +-----------------------------+
| assembly | | assembly_option | | assembly_option_link |
+-----------------+ +------------------------+ +-----------------------------+
| assembly_id (PK)| | assembly_option_id (PK)| | assembly_option_link_id (PK)|
| assembly_name | | assembly_option_name | | assembly_id (FK) |
| unit_cost | | option_number | | assembly_option_id (FK) |
+-----------------+ | unit_cost | +-----------------------------+
+------------------------+
Таблица "assembly_option_link" в основном определяет, какие опции доступны для каждой сборки.
Теперь для таблиц «цитата»:
+-----------------+ +------------------------+
| quote | | quote_assembly |
+-----------------+ +------------------------+
| quote_id (PK) | | quote_assembly_id (PK) |
| quote_name | | assembly_id (FK) |
+-----------------+ | quantity |
+------------------------+
Теперь самое сложное - как сохранить любые выбранные параметры. Должен ли я расширить таблицу 'quote_assembly' всеми 50 полями опций, хотя это нарушает правила нормализации. Сборка никогда не будет выбрана со всеми 50 вариантами, так что это тоже кажется очень неэффективным. С другой стороны, это решение позволяет пользователю вводить форму непосредственно в таблицу, что упрощает кодирование.
Я думаю, что «нормализованным» решением было бы создать еще одну таблицу, подобную этой:
+------------------------------+
| quote_assembly_option |
+------------------------------+
| quote_assembly_option_id (PK)|
| quote_assembly_id (FK) |
| assembly_option_id (FK) |
| quantity |
+------------------------------+
Это решение означает, что сохраняются только выбранные параметры. Кроме того, вместо сохранения option_number, я могу сохранить фактический «assembly_option_id». Это упрощает вычисление общей стоимости цитаты, поскольку мне не нужно конвертировать между 'option_number' и 'assembly_option_id', чтобы посмотреть стоимость опции сборки. Однако основным недостатком этого решения является то, что оно плохо сочетается с формой ввода пользователя. Я думаю, что мне нужно будет применить какое-то причудливое кодирование, чтобы связать форму с таблицами.
Кто-нибудь может предложить какие-либо советы по дизайну здесь, пожалуйста? Надеюсь, я достаточно хорошо объяснил себя.
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ
Это также подробный отчет по предложениям, который расширяет любые выбранные параметры в виде отдельных позиций под основной сборкой. Например:
+---------------------------------+------------+----------+------------+
| assembly | unit cost | quantity | total cost |
+---------------------------------+------------+----------+------------+
| VSD55 | £10'000 | 2 | £20'000 |
| - Seal leak protection | £ 5'000 | 1 | £ 5'000 | <-option 1
| - Motor over temp protection | £ 500 | 1 | £ 500 | <-option 2
+---------------------------------+------------+----------+------------+
| | | | £25'500 |
+---------------------------------+------------+----------+------------+
Последний вариант, который вы дадите, - это то, как я поступил бы с ним. И вернуть две сгруппированные таблицы, одну для «основной строки» и одну для собранных «существует ли» строк для 50 столбцов. Предполагая, что вы можете легко сопоставить опцию с соответствующим идентификатором столбца (похоже, вы можете это сделать без особых трудностей).
Это было бы достаточно просто для итерации, предполагая, что такой язык, как C #, где у вас есть доступный LINQ, и т. Д. Это достаточно просто сделать, даже если они включают в себя небольшой цикл (это код пользовательского интерфейса, это нужно сделать в какой-то момент ). Или вы могли бы сделать поворот в базе данных, прежде чем вернуться ... это было бы быстрее. Но это все равно будет поддерживать сложность.
Но твой дизайн звучит для меня правильно.
источник
Добавление вашей дополнительной таблицы мне тоже кажется вполне обоснованным.
Когда я решал похожую проблему, я решил сохранить дерево в таблице order_lines. Если вы рассматривали что-либо подобное, у меня было:
дополнительное
parent_id
поле дляorder_lines
и внешний ключ, чтобы(parent_id, product_id)
ссылаться(order_line_id, product_id)
Ограничение проверки для создания опции подразумевает родителя (в моем случае
check((option_id is not null) = (parent_id is not null))
).Другими словами, я позволил интерфейсу сказать, как все должно храниться:
С точки зрения пользовательского интерфейса это казалось правильным. Но это быстро показалось неправильным с точки зрения бизнес-правил в том смысле, что в будущем появилось множество проблем. (Мне приходилось иметь дело со всеми видами особых случаев в триггерах.)
Так что не рекомендуется ... Насколько я сталкивался с подобными случаями, ваш нынешний подход будет менее подвержен проблемам в будущем.
источник