Я составляю список элементов по категориям, проблема в том, что элемент может быть в нескольких категориях. Как лучше всего хранить элементы в категориях и как перечислить все элементы в категории и ее дочерних категориях? Я использую Zend Framework и MySQL для решения этой проблемы.
Спасибо за ответы.
Извините за мой английский :)






Итак, у вас есть иерархия категорий, да? Это один уровень (категория и дочерняя категория) или любое количество (дети могут иметь детей и т. д.)? Это повлияет на решение.
Как правило, вы бы смоделировали что-то подобное с помощью отношения «многие ко многим», например:
CREATE TABLE Item(
item_id INT NOT NULL,
item_name VARCHAR(255) NOT NULL
)
CREATE TABLE Category(
category_id INT NOT NULL,
category_name VARCHAR(255) NOT NULL
)
CREATE TABLE Item_Category(
item_id INT NOT NULL REFERENCES Item(item_id),
category_id INT NOT NULL REFERENCES Category(category_id)
)
Запись в «Item_Category» означает, что указанный элемент находится в указанной категории. Затем вы можете объединить 2 (или 3) из этих таблиц, чтобы перечислить, какие элементы относятся к каким категориям:
SELECT I.*
FROM Item I
INNER JOIN Item_Category IC ON I.item_id = IC.item_id
INNER JOIN Category C on IC.category_id = C.category_id
WHERE
C.category_name = 'MyCategory'
Или какие категории есть у предмета:
SELECT C.*
FROM Category C
INNER JOIN Item_Category IC.category_id = C.category_id
INNER JOIN Item I on IC.item_id = I.item_id
WHERE
I.item_name = 'MyItem'
Если в категориях есть иерархия, это можно выразить с помощью рекурсивной связи в таблице категорий, например:
CREATE TABLE Category(
category_id INT NOT NULL,
category_name VARCHAR(255) NOT NULL,
parent_category_id INT NOT NULL REFERENCES Category(category_id)
)
Это усложняет ситуацию, потому что вам нужно использовать рекурсивные запросы, чтобы получить все записи для категории и ее дочерних элементов. Более простой способ, если у вас есть только два уровня категорий, это просто сделать его вторым полем в таблице категорий, например:
CREATE TABLE Category(
category_id INT NOT NULL,
category_name VARCHAR(255) NOT NULL,
subcategory_name VARCHAR(255) NULL
)
если элемент может быть в нескольких категориях, то это не «категории». они больше похожи на теги.
используйте отношения "многие ко многим" между вашими элементами и вашими тегами. если вам нужна иерархия тегов, дерзайте; но это обычно излишне и очень редко добавляет ценности.
Как правило, лучшее решение, которое я нашел, которое работает в большинстве ситуаций, - это просто использовать поле parent_id в таблице категорий. Таким образом, вам понадобится только одна таблица категорий. Это будет поддерживать любое количество уровней или только один, если хотите (в этом случае в вашем коде необходимо предотвратить возможность создания третьего уровня категории).
Например: CREATE TABLE category (
id INT NOT NULL AUTO_INCREMENT,
parent_id INT NOT NULL DEFAULT '0'
name VARCHAR(255) NOT NULL
)
Так проще. Любая категория с parent_id, равным 0, будет вашим самым верхним уровнем. Если у вас есть категория, идентификатор которой равен 1, и вы создаете подкатегорию, ее parent_id будет равен 1 и т. д.
И чтобы было ясно, в этой последней версии таблицы категорий есть одна запись на подкатегорию. Так что на самом деле ее следует называть таблицей подкатегорий с PK "subcategory_id".