Какую структуру БД я должен использовать для сайта с бесконечной подкатегорией? - PullRequest
3 голосов
/ 13 сентября 2009

Например, «Dole Banana» является своего рода продуктом, он указан в категории «Бананы», когда я открываю категорию «Фрукты», я хочу видеть «Dole Banana».

+ Food
|--+ Fruits
|------+ Bananas   
|------+ Apples
|--+ Vegetables
|------+ Onion
|------+ Spinach

Ответы [ 8 ]

3 голосов
/ 13 сентября 2009

Я обычно использовал левый-правый деревья , которые очень хорошо адаптированы к запросам базы данных. У вас есть parentId, левое и правое значение для каждого узла. Каждый дочерний узел имеет левое / правое значение, которое находится между родительскими узлами слева и справа, что позволяет очень легко найти, например, всех дочерних / родительских узлов. Это немного увеличивает накладные расходы на вставки, но не должно быть слишком сильным, если вы не вставите много.

Редактировать: только слово предупреждения, вам нужно выполнить операции вставки / обновления в заблокированной транзакции, иначе дерево может испортиться.

3 голосов
/ 13 сентября 2009

Если вы ищете онлайн-ресурсы, посвященные этой проблеме, «Хранение дерева в базе данных» будет хорошей поисковой фразой.

Что касается решения, обратите внимание, что каждая подкатегория может иметь одну или нулевую родительскую категорию. Следовательно, все дерево может быть сохранено в одной само-реферируционной таблице с полем «родитель».

Используя ваше дерево примеров:

 ID  | PARENT | NAME
-----+--------+-------------
  1  |  null  | Food
  2  |   1    | Fruits
  3  |   2    | Bananas
  4  |   2    | Apples
  5  |   1    | Vegetables
  6  |   5    | Onion
  7  |   5    | Spinach
1 голос
/ 13 сентября 2009

Таблица "Категории" с 3 полями.

  1. CategoryId не нулевой (первичный ключ)
  2. ParentCategoryId null
  3. CategoryName not null

Чтобы получить все корневые категории

select * from Categories where ParentCategoryId is null

Чтобы получить все подкатегории определенной категории:

select * from Categories where ParentCategoryId = 12
0 голосов
/ 16 сентября 2009

Вот другой подход, который может быть полезен для вас. У него чуть больше затрат на обслуживание, чем у подхода PARENT_ID или lft / rght, но поиск намного проще (и быстрее).

Dole бананы могут быть в таблице продуктов. У вас есть один category_id для продукта.

У нас было требование разрешить несколько категорий для продукта. Это привело нас к созданию таблицы соединений category_products, в которой продукт может иметь несколько соединенных строк. Затем мы должны были решить, есть ли бананы Dole только в бананах, или в бананах и всех их родителях. Поскольку скорость поиска была критической, мы поместили бананы пособия по безработице в его категории и все их родительские категории. Есть три объединения продуктов категории для бананов пособия по безработице.

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

0 голосов
/ 13 сентября 2009

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

0 голосов
/ 13 сентября 2009
    CREATE TABLE [dbo].[Category](
    [CategoryId] [int] NOT NULL,
    [ParentCategoryId] [int] NULL,
    [CategoryName] [nvarchar](50) NOT NULL,
     CONSTRAINT [PK_Category] PRIMARY KEY CLUSTERED 
    (
        [CategoryId] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON 

[PRIMARY]

GO

ALTER TABLE [dbo].[Category]  WITH CHECK ADD  CONSTRAINT [FK_Category_Category] FOREIGN KEY([ParentCategoryId])
REFERENCES [dbo].[Category] ([CategoryId])
GO

ALTER TABLE [dbo].[Category] CHECK CONSTRAINT [FK_Category_Category]
GO
0 голосов
/ 13 сентября 2009

Если вы имеете в виду бесконечное количество уровней, то таблица с самореференциями может быть рекурсивной. Пример: StuffID, StuffName, StuffParentID (от FK до Stuff ID)

Для конечного числа фиксированные таблицы: родитель-ребенок-внук

0 голосов
/ 13 сентября 2009

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

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