Проблема, которую вы описываете, представляет собой типичную открытую схему или вертикальную базу данных, которая является классическим вариантом использования 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
с гораздо более гибкими схемами.