無限のサブカテゴリを持つサイトにどのようなDB構造を使用する必要がありますか?
-
07-07-2019 - |
質問
たとえば、「Dole Banana」など。は一種の製品で、「バナナ」の下にリストされています。カテゴリ、「果物」を開くとカテゴリ、「Dole Banana」を表示したい。
+ Food
|--+ Fruits
|------+ Bananas
|------+ Apples
|--+ Vegetables
|------+ Onion
|------+ Spinach
解決
通常、左右ツリーを使用しました。データベースクエリに非常によく適合しています。各ノードにparentId、leftおよびrightの値があります。各ノードの子には、親ノードの左と右の間にある左/右の値があります。これにより、たとえばノードのすべての子/親を簡単に見つけることができます。挿入時にわずかなオーバーヘッドが発生しますが、たくさん挿入しない限り、それほど大きな影響はありません。
編集:警告の言葉だけですが、ロックされたトランザクションで挿入/更新操作を行う必要があります。そうしないと、ツリーが混乱する可能性があります。
他のヒント
この問題に対処するオンラインリソースを探している場合、「データベースにツリーを保存する」適切な検索フレーズになります。
ソリューションについては、各サブカテゴリに1つまたは0の親カテゴリを含めることができることに注意してください。そのため、ツリー全体を「親」という単一の自己参照テーブルに格納できます。フィールド。
サンプルツリーの使用:
ID | PARENT | NAME
-----+--------+-------------
1 | null | Food
2 | 1 | Fruits
3 | 2 | Bananas
4 | 2 | Apples
5 | 1 | Vegetables
6 | 5 | Onion
7 | 5 | Spinach
表"カテゴリー" 3つのフィールド。
- CategoryIdがnullではない(主キー)
- ParentCategoryId null
- CategoryNameはnullではありません
すべてのルートカテゴリを取得するには
select * from Categories where ParentCategoryId is null
特定のカテゴリのすべてのサブカテゴリを取得するには:
select * from Categories where ParentCategoryId = 12
parent_category_idで単純なテーブル構造を使用し、再帰でツリー全体を取得するか、左/右の値を実装し、事前順序ツリートラバーサルメソッドを使用してツリー全体をフェッチできます。
レベルの数が無限であれば、再帰可能な自己参照テーブルです。例:StuffID、StuffName、StuffParentID(FKからStuff ID)
有限数の場合、固定テーブル:parent-child-grandchild
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
無限階層の場合、修正された先行順序ツリートラバーサルアルゴリズム
これは、あなたに役立つかもしれない別のアプローチです。 PARENT_IDまたはlft / rghtアプローチよりも保守コストがわずかに高くなりますが、取得ははるかに簡単です(そしてより高速です)。
ドールバナナは製品テーブルに含めることができます。製品に対して1つのcategory_idがあります。
製品に複数のカテゴリを許可する必要がありました。これにより、category_products結合テーブルが作成され、製品に複数の結合行を含めることができます。次に、ドールバナナをバナナだけに入れるか、バナナとそのすべての親に入れるかを決めなければなりませんでした。検索の速度が重要であったため、ドールとそのすべての親カテゴリーにドールバナナを入れました。ドールバナナには3つのカテゴリと製品の結合があります。
この構造を使用すると、任意のカテゴリからすべてのアイテムを簡単にすばやく返すことができ、クエリは1つだけです。 PARENT_IDアプローチではこれを実行できません(親、祖父母などをハードコーディングしない限り)。カテゴリの追加は簡単です。製品を分類するには、結合テーブルに複数の行を挿入する必要があります。カテゴリの削除と移動は少し複雑です。