Quel type de structure de base de données dois-je utiliser pour un site comportant une sous-catégorie infinie?
-
07-07-2019 - |
Question
Par exemple, "Dole Banana" est un type de produit, il est répertorié sous le symbole "Bananes". catégorie, lorsque j'ouvre le "Fruits" catégorie "Je veux voir" Dole Banana ".
+ Food
|--+ Fruits
|------+ Bananas
|------+ Apples
|--+ Vegetables
|------+ Onion
|------+ Spinach
La solution
J'ai généralement utilisé des arborescences gauche-droite , qui sont très bien adaptés aux requêtes de base de données. Vous avez une valeur parentId, left et right pour chaque nœud. Chaque nœud enfant a une valeur gauche / droite située entre les nœuds parents gauche et droite, ce qui facilite la recherche, par exemple, de tous les enfants / parents d'un nœud. Cela donne un léger surcoût sur les insertions, mais cela ne devrait pas avoir trop d'impact à moins d'insérer beaucoup.
Modifier: un simple avertissement cependant, vous devez effectuer les opérations d’insertion / mise à jour dans une transaction verrouillée, sinon l’arborescence peut être gâchée.
Autres conseils
Si vous recherchez des ressources en ligne permettant de résoudre ce problème, " Stockage d'un arbre dans une base de données " serait une bonne phrase de recherche.
En ce qui concerne la solution, notez que chaque sous-catégorie peut avoir une ou deux catégories parentes. Par conséquent, l’arbre entier peut être stocké dans une seule table auto-référencée avec un "parent". champ.
En utilisant votre exemple d'arborescence:
ID | PARENT | NAME
-----+--------+-------------
1 | null | Food
2 | 1 | Fruits
3 | 2 | Bananas
4 | 2 | Apples
5 | 1 | Vegetables
6 | 5 | Onion
7 | 5 | Spinach
Une table " Catégories " avec 3 champs.
- CategoryId non null (clé primaire)
- ParentCategoryId null
- Nom de catégorie non nul
Pour obtenir toutes les catégories de racines
select * from Categories where ParentCategoryId is null
Pour obtenir toutes les sous-catégories d'une catégorie spécifique:
select * from Categories where ParentCategoryId = 12
Vous pouvez utiliser une structure de table simple avec parent_category_id et récupérer une arborescence complète avec récursion ou implémenter des valeurs gauche / droite et récupérer une arborescence complète à l'aide de la méthode de parcours de l'arborescence préordonnée.
Si vous voulez dire un nombre infini de niveaux, alors une table d’auto-référencement qui peut être récursive. Exemple: StuffID, StuffName, StuffParentID (FK to Stuff ID)
Pour un nombre fini, tables fixes: parent-enfant-petit-enfant
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
Pour une hiérarchie infinie, utilisez l’ algorithme modifié de traversée de l'arborescence de pré-ordre
Voici une approche différente qui pourrait vous être utile. Les coûts de maintenance sont légèrement supérieurs à ceux de l’approche PARENT_ID ou lft / rght, mais la récupération est beaucoup plus facile (et plus rapide).
Les bananes Dole peuvent être dans la table des produits. Vous avez un seul category_id pour un produit.
Nous avions l'obligation de permettre plusieurs catégories pour un produit. Cela nous a conduit à avoir une table de jonction categories_products, où le produit pourrait avoir plusieurs lignes jointes. Ensuite, nous devions décider si nous avions des bananes Dole dans les bananes uniquement, ou dans les bananes et tous ses parents. La rapidité de récupération étant cruciale, nous avons classé les bananes dole dans ses catégories et dans toutes leurs catégories parentes. Il existe trois catégories de produits joints pour les bananes dole.
À l'aide de cette structure, le renvoi de tous les éléments de n'importe quelle catégorie est facile et rapide, une seule requête. Vous ne pouvez pas faire cela dans l'approche PARENT_ID (sauf si vous codez en dur les parents, les grands-parents, etc.) L'ajout d'une catégorie est facile. La catégorisation d'un produit nécessite l'insertion de plusieurs lignes dans la table de jointure. La suppression et le déplacement de catégories sont un peu plus compliqués.