假设我必须将以下信息存储在我的数据库中,
现在我的数据库表将被设计和结构如下,
以后,如果我必须添加另一个子类别级别,我将如何在不更改数据库结构的情况下实现这一目标?
我听说过将列定义为表中的行数据,并稍后使用数据透视来提取详细信息...这是实现此目的的正确方法吗?
有人可以启发我或指导我正确的方向吗?提前致谢...
:)
最佳答案
当要生成新级别时,向表中添加更多列将很困难。最好的方法是使用 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
找到其父级。 s 并使用层次结构查询查找 parent 的 parent 。
在 Category
表,类别为 ParentId
为 null(即没有parentId)将是 MainCategory
以及其他带有 ParentId
的项目将在SubCategory
下.
编辑:
您需要如何更改表,因为根据您当前的架构,您无法向第一个表添加列,因为子类别的数量可能会不断变化。即使您按照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
table 和保存Food Industry's
ID为ParentId
对于 Food
和Beverage
。就这样。
现在如果您想进行旋转,可以按照以下步骤操作。
<强>1。从列中获取值以将这些值显示为数据透视表中的列
DECLARE @cols NVARCHAR (MAX)
SELECT @cols = COALESCE (@cols + ',[' + COLS + ']', '[' + COLS + ']')
FROM (SELECT DISTINCT COLS,[LEVEL] FROM #NEWTABLE) PV
ORDER BY [LEVEL]
<强>2。现在使用下面的 PIVOT 查询
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
- Click here查看结果
数据透视后您将得到以下结果
注意
如果您想要所有记录而不考虑某个项目,请删除
WHERE
里面的条款CTE
。 Click here查看结果。现在我已将数据透视表中的列顺序提供为
DESC
即,它显示顶级父项......项目的父项。如果您想首先显示 Item 的父级,然后是下一级,最后是顶级父级,您可以更改DESC
里面ROW_NUMBER()
至ASC
。 Click here查看结果。
关于sql-server - 设计层次结构表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28086236/