mar*_*ate 17 sql-server cte t-sql recursive
这是一个装配树,我想使用递归T-SQL查询(大概CTE)和下面的预期结果进行搜索。我想知道给定任何零件的每个组件的总量。
这意味着如果我搜索“铆钉”,我想知道程序集中每个级别的总数,而不仅仅是直接子项计数。
Assembly (id:1)
|
|-Rivet
|-Rivet
|-SubAssembly (id:2)
| |
| |-Rivet
| |-Bolt
| |-Bolt
| |-SubSubAssembly (id:3)
| |
| |-Rivet
| |-Rivet
|
|-SubAssembly (id:4)
|-Rivet
|-Bolt
DESIRED Results
-------
ID, Count
1 , 6
2 , 3
3 , 2
4 , 1
Run Code Online (Sandbox Code Playgroud)
目前,我可以获得直接父母,但想知道如何扩展我的 CTE 以允许我向上滚动此信息。
With DirectParents AS(
--initialization
Select InstanceID, ParentID
From Instances i
Where i.Part = 'Rivet'
UNION ALL
--recursive execution
Select i.InstanceID, i.ParentID
From PartInstances i INNER JOIN DirectParents p
on i.ParentID = p.InstanceID
)
select ParentID, Count(instanceid) as Totals
from DirectParents
group by InstanceID, ParentID
Results
-------
ID, Count
1 , 2
2 , 2
3 , 2
4 , 1
Run Code Online (Sandbox Code Playgroud)
创建脚本
CREATE TABLE [dbo].[Instances] (
[InstanceID] NVARCHAR (50) NOT NULL,
[Part] NVARCHAR (50) NOT NULL,
[ParentID] NVARCHAR (50) NOT NULL, );
INSERT INTO Instances
Values
(1, 'Assembly', 0),
(50, 'Rivet', 1),
(50, 'Rivet', 1),
(2, 'SubAssembly', 1),
(50, 'Rivet', 2),
(51, 'Bolt', 2),
(51, 'Bolt', 2),
(3, 'SubSubAssembly', 2),
(50, 'Rivet', 3),
(50, 'Rivet', 3),
(4, 'SubAssembly2', 1),
(50, 'Rivet', 4),
(51, 'Bolt', 4)
Run Code Online (Sandbox Code Playgroud)
Jul*_*eur 16
此递归 CTE ( SQL Fiddle ) 应该适用于您的示例:
WITH cte(ParentID) AS(
SELECT ParentID FROM @Instances WHERE [Part] = 'Rivet'
UNION ALL
SELECT i.ParentID FROM cte c
INNER JOIN @Instances i ON c.ParentID = i.InstanceID
WHERE i.ParentID > 0
)
SELECT ParentID, count(*)
FROM cte
GROUP BY ParentID
ORDER BY ParentID
;
Run Code Online (Sandbox Code Playgroud)
ParentID Count
1 6
2 3
3 2
4 1
Run Code Online (Sandbox Code Playgroud)
注意:您在评论中提到该问题仅包含一个简化的示例表,真实数据具有适当的索引并充分处理重复项和数据。
使用的数据(SQL Fiddle):
DECLARE @Instances TABLE(
[InstanceID] int NOT NULL
, [Part] NVARCHAR (50) NOT NULL
, [ParentID] int NOT NULL
);
INSERT INTO @Instances([InstanceID], [Part], [ParentID])
VALUES
(1, 'Assembly', 0)
, (50, 'Rivet', 1)
, (50, 'Rivet', 1)
, (2, 'SubAssembly', 1)
, (50, 'Rivet', 2)
, (51, 'Bolt', 2)
, (51, 'Bolt', 2)
, (3, 'SubSubAssembly', 2)
, (50, 'Rivet', 3)
, (50, 'Rivet', 3)
, (4, 'SubAssembly2', 1)
, (50, 'Rivet', 4)
, (51, 'Bolt', 4)
;
Run Code Online (Sandbox Code Playgroud)