使用sql进行递归计算以形成树

use*_*648 6 sql t-sql sql-server recursive-query

我正在研究一个简单的问题,并希望使用SQL来解决它.我有3个表类别,项目和关系表CategoryItem.我需要返回每个类别的项目数,但扭曲是类别按父子关系排列,子类别中的项目数应该添加到其父类别中的计数.请使用SQL考虑下面的示例数据和预期的结果集.

Id  Name    ParentCategoryId
1   Category1   Null
2   Category1.1 1
3   Category2.1 2
4   Category1.2 1
5   Category3.1 3

ID  CateoryId   ItemId
1   5              1
2   4              2
3   5              2
4   3              1
5   2              3
6   1              1
7   3              2
Run Code Online (Sandbox Code Playgroud)

结果:

CategoryNAme     Count
Category1          7
Category1.1        5
Category2.1        4
Category1.2        1
Category3.1        2
Run Code Online (Sandbox Code Playgroud)

我可以在我的业务层中执行此操作,但由于数据大小,性能并非最佳.我希望如果我能在数据层中做到这一点,我将能够大大提高性能.

在此先感谢您的回复

Sid*_*sud 3

您的表格和示例数据

create table #Category(Id int identity(1,1),Name Varchar(255),parentId int)
INSERT INTO #Category(Name,parentId) values
('Category1',null),('Category1.1',1),('Category2.1',2),
('Category1.2',1),('Category3.1',3)

create table #CategoryItem(Id int identity(1,1),categoryId int,itemId int)
INSERT INTO #CategoryItem(categoryId,itemId) values
(5,1),(4,2),(5,2),(3,1),(2,3),(1,1),(3,2)

create table #Item(Id int identity(1,1),Name varchar(255))
INSERT INTO #Item(Name) values('item1'),('item2'),('item3')
Run Code Online (Sandbox Code Playgroud)

通过递归公用表表达式检查父级的所有子级

;WITH CategorySearch(ID, parentId) AS
(
SELECT ID, ID AS ParentId FROM #Category
UNION ALL
SELECT CT.Id,CS.parentId  FROM #Category CT
INNER JOIN CategorySearch CS ON CT.ParentId = CS.ID
)
select * from CategorySearch order by 1,2
Run Code Online (Sandbox Code Playgroud)

输出:针对父级的所有子级记录

ID  parentId
1   1
2   1
3   1
4   1
5   1
2   2
3   2
5   2
3   3
5   3
4   4
5   5
Run Code Online (Sandbox Code Playgroud)

对结果的最终查询,计算类别及其子类别的所有项目。

;WITH CategorySearch(ID, parentId) AS
(
SELECT ID, ID AS ParentId FROM #Category
UNION ALL
SELECT CT.Id,CS.parentId  FROM #Category CT
INNER JOIN CategorySearch CS ON CT.ParentId = CS.ID
)
SELECT CA.Name AS CategoryName,count(itemId) CountItem
FROM #Category CA 
INNER JOIN CategorySearch CS ON CS.ParentId = CA.id
INNER JOIN #CategoryItem MI ON MI.CategoryId =CS.ID
GROUP BY CA.Name
Run Code Online (Sandbox Code Playgroud)

输出:

CategoryName    CountItem
Category1           7
Category1.1         5
Category1.2         1
Category2.1         4
Category3.1         2
Run Code Online (Sandbox Code Playgroud)