Postgres база данных: как моделировать несколько атрибутов, которые могут иметь также несколько значений и иметь отношения с двумя другими объектами - PullRequest
0 голосов
/ 23 января 2020

У меня есть три объекта: Предметы, Категории и Атрибуты.

Item может быть одним или несколькими Categories, поэтому существует отношение N: M.

Item               ItemCategories                   Categories     

id name            item_id category_id             id    name     
1  alfa               1         1                   1   chipset
                      1         2                   2   interface 

Item может иметь несколько Attributes в зависимости от «Категории», в которой они находятся.

Например, элементы в Category 'chipset' могут иметь атрибуты: 'interface', ' memory '' tech '.

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

Например: «memory» может быть только ddr2, ddr3 , ddr4.

Attributes                                 CategoryAttributes

id name     values                          category_id attribute_id    
1  memory   {ddr2, ddr3, ddr4}              1              1

Item, который находится в наборе микросхем Category, имеет доступ к Attribute и может иметь только значение Null или предопределенное значение атрибута.

Я подумал использовать Enum или Json для значений атрибутов, но у меня есть два других условия:

ItemAttributes

item_id attribute_id   value
 1        1          {ddr2, ddr4}

1) Если появляется атрибут в 2 категориях, и он находится в обеих категориях, только один раз атрибут может быть показан.

2) Мне нужно использовать значение с rank, поэтому, если для элемента появляются два соответствующих значения атрибута, ранг должен быть больше, если он только один, или значение не существует.

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

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

1 Ответ

2 голосов
/ 01 февраля 2020

Проблема, которую вы описываете, представляет собой типичную открытую схему или вертикальную базу данных, которая является классическим вариантом использования c для некоторой модели EAV.

EAV - это сложная, но мощная парадигма, которая допускает потенциально открытую схему при соблюдении нормальных форм базы данных и позволяет иметь то, что вам нужно: иметь переменное количество атрибутов в зависимости от спецификации c экземпляры одного и того же лица.

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

Вы можете взглянуть на Модель БД Magento , истинную ссылку в чистом формате EAV или Википедия , но, вероятно, вы можете сделать что позже, а сейчас вам просто нужны основы:

Идея основы c заключается в том, чтобы хранить атрибуты и их соответствующие значения в виде строк, а не столбцов, в одной таблице.

В более простой реализации таблица имеет как минимум три столбца: entity (обычно внешний ключ к объекту или тип / категория объекта), attribute (это n - строка, внешний ключ в более сложных системах) и value.

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

Item table                 Attributes table

+------+--------------+   +-------------+-----------+-------------+
|   id | name         |   |     item_id | attribute | value       |
+------+--------------+   +-------------+-----------+-------------+
|    1 | "hard drive" |   |           2 |   "color" |       "red" | 
+------+--------------+   +-------------+-----------+-------------+
|    2 | "lipstick"   |   |           2 |   "price" |          10 | 
+------+--------------+   +-------------+-----------+-------------+
                          |           1 | "capacity"|       "1TB" | 
                          +-------------+-----------+-------------+
                          |           1 |   "price" |         200 | 
                          +-------------+-----------+-------------+

 So for every item, you can have a list of attributes. 

Поскольку ваша модель более сложна, она имеет Еще несколько ограничений, поэтому нам нужно адаптировать эту модель.

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

При этом вы получите что-то вроде

Таблица категорий Список идентификаторов и имен категорий

+------+--------------+ 
|   id | name         |  
+------+--------------+ 
|    1 | "chipset"    | 
+------+--------------+ 
|    2 | "interface"  | 
+------+--------------+ 

Таблица атрибутов Список идентификаторов атрибутов и их имя

+------+--------------+ 
|   id | name         |  
+------+--------------+ 
|    1 | "interface"  | 
+------+--------------+ 
|    2 | "memory"     | 
+------+--------------+ 
|    3 | "tech"       | 
+------+--------------+
|    4 | "price"      | 
+------+--------------+

Таблица атрибутов категории Какая категория имеет какие атрибуты. Обратите внимание, что один атрибут (т.е. 4) может принадлежать 2 категориям

+--------------+--------------+ 
| attribute_id | category_id  |  
+--------------+--------------+ 
|            1 |            1 | 
+--------------+--------------+ 
|            2 |            1 | 
+--------------+--------------+ 
|            3 |            1 | 
+--------------+--------------+ 
|            4 |            1 | 
+--------------+--------------+ 
|            4 |            2 | 
+--------------+--------------+ 

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

+----------+--------------+--------+
| value_id | attribute_id | value  |
+-------------+-----------+--------+
|        1 |            2 | "ddr2" | 
+----------+--------------+--------+
|        2 |            2 | "ddr3" | 
+----------+--------------+--------+
|        3 |            2 | "ddr4" | 
+----------+--------------+--------+
|        4 |            3 |"tech_1"| 
+----------+--------------+--------+
|        5 |            3 |"tech_2"| 
+----------+--------------+--------+
|        6 |     ...      |   ...  | 
+----------+--------------+--------+
|        7 |     ...      |   ...  | 

И, наконец, что Вы можете себе представить, что в таблице

Item-Attribute будет указано одно значение атрибута на строку

+----------+--------------+-------+
| item_id  | attribute_id | value |
+----------+-----------+----------+
|        1 |            2 |     1 | 
+----------+--------------+-------+
|        1 |            2 |     3 | 
+----------+--------------+-------+

Meaning that item 1, for attribute 2 (`memory`), has values 1 and 3 (`ddr2` and `ddr3`)

Это будет охватывать все ваши условия:

  • Количество атрибутов не ограничено, настолько велико, насколько необходимо и не фиксировано
  • Вы можете четко определить, какая категория имеет какие атрибуты
  • Две категории могут иметь один и тот же атрибут
  • Если 1 элемент принадлежит двум категориям, имеющим один и тот же атрибут, вы можете отобразить только одну (ie SELECT * from Category-Attribute where category_id in (SELECT category_id from ItemCategories where item_id = ...) выдаст вам список допустимых атрибутов, только по одной из каждой, даже если 2 категории имеют одинаковые
  • Вы можете сделать rank, я думаю, что у меня недостаточно информации для этого запроса, но, будучи полностью нормализованной моделью, вы определенно можете получить ранг. У вас здесь почти полная модель, так что вы наверняка можете понять вне запроса.

Это очень похоже на модель, которую использует Magento. Он очень мощный, но, конечно, им может быть сложно управлять, но это лучший способ, если мы хотим сохранить строгую модель и убедиться, что она будет обеспечивать ограничения и что она будет принимать все функции SQL. Для менее строгих систем всегда можно выбрать go для базы данных NoSQL с гораздо более гибкими схемами.

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