让我们说我必须在我的数据库中存储以下信息,
现在我的数据库表的设计和结构都是这样的,
在以后的某个日子里,如果我必须添加另一个子类别级别,我将如何在不更改数据库结构的情况下实现这一目标?
我听说过将列定义为表中的行数据,并使用pivot来稍后提取详细信息......这是实现此目的的正确方法吗?
有人可以开导我或指导我正确的方向吗?提前谢谢......
:)
答案 0 :(得分:5)
当要生成新级别时,很难向表中添加更多列。最好的方法是使用Hierarchy table
维护Parent-Child relationship
。
表:Items
x----x------------------x------------x
| ID | Items | CategoryId |
|----x------------------x------------x
| 1 | Pepsi | 3 |
| 2 | Coke | 3 |
| 3 | Wine | 4 |
| 4 | Beer | 4 |
| 5 | Meals | 2 |
| 6 | Fried Rice | 2 |
| 7 | Black Forest | 7 |
| 8 | XMas Cake | 7 |
| 9 | Pinapple Juice | 8 |
| 10 | Apple Juice | 8 |
x----x------------------x------------x
表:Category
在类别表格中,您可以将类别添加到n
级别。在Items
表中,您可以存储最低级别的类别。例如,以Pepsi
为例 - 其categoryId
为3.在类别表中,您可以使用JOIN
找到其父级,并使用层次结构查询查找父级父级。
在Category
表格中,ParentId
的类别为空(没有parentId)将为MainCategory
,而ParentId
的其他项目将位于SubCategory
下{1}}。
编辑:
您需要如何更改表,因为根据您当前的架构,您无法将列添加到第一个表,因为Sub类别的数量可能会不断变化。即使您根据 Rhys Jones 答案创建表格,也必须使用字符串连接两个表格。加入字符串的问题在于,当需要更改Sub category
或Main category
名称时,您必须在每个表格中更改您将来遇到的麻烦并且不是很好数据库设计。所以我建议你遵循以下模式。
以下是获取子项目父项的查询。
DECLARE @ITEM VARCHAR(30) = 'Black Forest'
;WITH CTE AS
(
-- Finds the original parent for an ITEM ie, Black Forest
SELECT I.ID,I.ITEMS,C.CategoryId,C.Category,ParentId,0 [LEVEL]
FROM #ITEMS I
JOIN #Category C ON I.CategoryId=C.CategoryId
WHERE ITEMS = @ITEM
UNION ALL
-- Now it finds the parents with hierarchy level for ITEM
-- ie, Black Forest. This is called Recursive query, which works like loop
SELECT I.ID,I.ITEMS,C.CategoryId,C.Category,C.ParentId,[LEVEL] + 1
FROM CTE I
JOIN #Category C ON C.CategoryId=I.ParentId
)
-- Here we keep a column to show header for pivoting ie, CATEGORY0,CATEGORY1 etc
-- and keep these records in a temporary table #NEWTABLE
SELECT ID,ITEMS,CATEGORYID,CATEGORY,PARENTID,
'CATEGORY'+CAST(ROW_NUMBER() OVER(PARTITION BY ITEMS ORDER BY [LEVEL] DESC)-1 AS VARCHAR(4)) COLS,
ROW_NUMBER() OVER(PARTITION BY ITEMS ORDER BY [LEVEL] DESC)-1 [LEVEL]
INTO #NEWTABLE
FROM CTE
ORDER BY ITEMS,[LEVEL]
OPTION(MAXRECURSION 0)
以下是上述查询的结果
解释
Black Forest
位于Cake
。Cake
位于Bakery
之下。 Bakery
位于Food
。像这样,您可以为任意数量的级别创建子级或父级。现在,如果您要将父级添加到Food
和Beverage
,例如Food Industry
,只需将Food Industry
添加到Category
表并保留{{1} } Food Industry's
和ParentId
的ID为Food
。就这样。
现在,如果您想进行旋转,可以按照以下步骤进行操作。
<强> 1。从列获取值以将这些值显示为数据透视中的列
Beverage
<强> 2。现在使用以下PIVOT查询
DECLARE @cols NVARCHAR (MAX)
SELECT @cols = COALESCE (@cols + ',[' + COLS + ']', '[' + COLS + ']')
FROM (SELECT DISTINCT COLS,[LEVEL] FROM #NEWTABLE) PV
ORDER BY [LEVEL]
您将在数据透视后获得以下结果
注意
如果您想要所有记录而不管项目如何,请删除DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT * FROM
(
SELECT ITEMS, CATEGORY, COLS
FROM #NEWTABLE
) x
PIVOT
(
MIN(CATEGORY)
FOR COLS IN (' + @cols + ')
) p
ORDER BY ITEMS;'
EXEC SP_EXECUTESQL @query
内的WHERE
子句。 Click here查看结果。
现在我已在数据透视表中提供了CTE
列的顺序,即它显示了顶级父级.....项目的父级。如果您想首先显示项目的父级,最后是下级和顶级父级,您可以将DESC
内的DESC
更改为ROW_NUMBER()
。 Click here查看结果。
答案 1 :(得分:3)
根据您的架构,主要类别&#39;之间没有任何关系。和&#39;子类别&#39;但你的样本数据表明会有一种关系,即酒精是一种饮料等。这听起来像是一个类别的层次结构,在这种情况下你可以改为使用一个自引用的类别表;
create table dbo.Category (
CategoryID int not null constraint PK_Category primary key clustered (CategoryID),
ParentCategoryID int not null,
CategoryName varchar(100) not null
)
alter table dbo.Category add constraint FK_Category_Category foreign key(ParentCategoryID) references dbo.Category (CategoryID)
insert dbo.Category values (1, 1, 'Beverages')
insert dbo.Category values (2, 1, 'Soft Drink')
insert dbo.Category values (3, 1, 'Alcohol')
这样您就可以根据需要创建多个级别的类别。 ParentCategoryID = CategoryID的任何类别都是顶级类别。
希望这有帮助,
里斯
答案 2 :(得分:-1)
为了添加新的子类别,您应该将类别添加到表“ItemSubCategory1”,之后您可以轻松地将其添加到“饮料”表中。
例如: 如果有新的类别名称“Hot Drinks”和Beverages主要类别中的新项目“Coffee”(让CatId = 1,MainCatText ='Beverages'在ItemMainCategory表中)那么
INSERT INTO ItemSubCategory1(CatId,SubCatText) VALUES(4,'Hot Drinks')
INSERT INTO Drinks(ItemId,ItemName,ItemMainCategory,ItemSubCategory)
VALUES(5,'Coffee',1,4)