(CTE) 递归 SQL 查询

(CTE) Recursive SQL Query

我对一些与递归查询相关的问题感到困惑。
我正在使用 SQL 服务器 2012
我的场景, 位置是分层定义的, 每个位置都有自己的资产。
我的位置 table 赞;

Id  | Name | ParentLocationId
----+------+-----------------  
1   | L1   | NULL  
2   | L2   | 1  
3   | L3   | 1  
4   | L4   | 1  
5   | L5   | 1  
6   | L6   | 4  
7   | L7   | 4  
8   | L8   | 4  
9   | L9   | 2  
10  | L10  | 2  
11  | L11  | 6  
12  | L12  | 6  
13  | L13  | 6  

我的资产table喜欢;

    Id | AssetNo | Description | CurrentLocationId
-------+---------+-------------+------------------
    1  | AN001   |  ADesc      | 1  
    2  | AN002   | BDesc       | 1  

L1有1个,L2有2个,L3有0个,L4有3个,L5有5个,L6有5个,L7有1个, L8 有 0 个,L9 有 3 个,L10 有 2 个,L11 有 5 个,L12 有 3 个,L13 有 6 个资产

我的问题是,如何获取所选位置的总数 资产数量下降 1 级?

例如;选定的 LocationId = 1 (L1) 样本输出是;

    Id | Name | Qty 
-------+------+----- 
    2  | L2   | 7  
    3  | L3   | 0  
    4  | L4   | 23  
    5  | L5   | 5  

另一个例子;选定的 LocationId = 4 (L4)

Id | Name | Qty  
---+------+-----
6  | L6   | 19  
7  | L7   | 1  
8  | L8   | 0  

我试着写了一个查询,

WITH recursiveTable
    AS (SELECT *
         FROM   location l
         WHERE  ParentLocationId = 1
         UNION ALL
         SELECT l.*
         FROM   location l
                INNER JOIN recursiveTable r
                        ON r.Id = l.ParentLocationId),
     allLocations
     AS (SELECT *
         FROM   recursiveTable
         UNION
         SELECT *
         FROM   Location
         WHERE  Id = 0),
     resultset 
     AS (SELECT r.NAME AS LocationName,
                a.*
         FROM   allLocations r
         INNER JOIN Asset a ON a.CurrentLocationId = r.Id
         WHERE  r.DataStatus = 1)

select CurrentLocationId
       ,min(LocationName) as LocationName
       ,count(Id) as NumberOfAsset
from resultset
group by CurrentLocationId

额外的;

Create Table Location
    (
      Id int,
      Name nvarchar(100),
      Description nvarchar(250),
      ParentLocationId int,
      DataStatus int
    )

    Create Table Asset
    (
      Id int,
      AssetNo nvarchar(50),
      Description nvarchar(250),
      CurrentLocationId int,
      DataStatus int
    )

    Insert Into Location Values(1,'L1','LDesc1',NULL,1)
    Insert Into Location Values(2,'L2','LDesc2',1,1)
    Insert Into Location Values(3,'L3','LDesc3',1,1)
    Insert Into Location Values(4,'L4','LDesc4',1,1)
    Insert Into Location Values(5,'L5','LDesc5',1,1)
    Insert Into Location Values(6,'L6','LDesc6',4,1)
    Insert Into Location Values(7,'L7','LDesc7',4,1)
    Insert Into Location Values(8,'L8','LDesc8',4,1)
    Insert Into Location Values(9,'L9','LDesc9',2,1)
    Insert Into Location Values(10,'L10','LDesc10',2,1)
    Insert Into Location Values(11,'L11','LDesc11',6,1)
    Insert Into Location Values(12,'L12','LDesc12',6,1)
    Insert Into Location Values(13,'L13','LDesc13',6,1)

    Insert Into Asset Values (1,'FDB-001','Desc1',1,1)
    Insert Into Asset Values (2,'FDB-002','Desc2',2,1)
    Insert Into Asset Values (3,'FDB-003','Desc3',2,1)
    Insert Into Asset Values (4,'FDB-004','Desc4',4,1)
    Insert Into Asset Values (5,'FDB-005','Desc5',4,1)
    Insert Into Asset Values (6,'FDB-006','Desc6',4,1)
    Insert Into Asset Values (7,'FDB-007','Desc7',5,1)
    Insert Into Asset Values (8,'FDB-008','Desc8',5,1)
    Insert Into Asset Values (9,'FDB-009','Desc9',5,1)
    Insert Into Asset Values (10,'FDB-010','Desc10',5,1)
    Insert Into Asset Values (11,'FDB-011','Desc11',5,1)
    Insert Into Asset Values (12,'FDB-012','Desc12',6,1)
    Insert Into Asset Values (13,'FDB-013','Desc13',6,1)
    Insert Into Asset Values (14,'FDB-014','Desc14',6,1)
    Insert Into Asset Values (15,'FDB-015','Desc15',6,1)
    Insert Into Asset Values (16,'FDB-016','Desc16',6,1)
    Insert Into Asset Values (17,'FDB-017','Desc17',7,1)
    Insert Into Asset Values (18,'FDB-018','Desc18',9,1)
    Insert Into Asset Values (19,'FDB-019','Desc19',9,1)
    Insert Into Asset Values (20,'FDB-020','Desc20',9,1)
    Insert Into Asset Values (21,'FDB-021','Desc21',10,1)
    Insert Into Asset Values (22,'FDB-022','Desc22',10,1)
    Insert Into Asset Values (23,'FDB-023','Desc23',11,1)
    Insert Into Asset Values (24,'FDB-024','Desc24',11,1)
    Insert Into Asset Values (25,'FDB-025','Desc25',11,1)
    Insert Into Asset Values (26,'FDB-026','Desc26',11,1)
    Insert Into Asset Values (27,'FDB-027','Desc27',11,1)
    Insert Into Asset Values (28,'FDB-028','Desc28',12,1)
    Insert Into Asset Values (29,'FDB-029','Desc29',12,1)
    Insert Into Asset Values (30,'FDB-030','Desc30',12,1)
    Insert Into Asset Values (31,'FDB-031','Desc31',13,1)
    Insert Into Asset Values (32,'FDB-032','Desc32',13,1)
    Insert Into Asset Values (33,'FDB-033','Desc33',13,1)
    Insert Into Asset Values (34,'FDB-034','Desc34',13,1)
    Insert Into Asset Values (35,'FDB-035','Desc35',13,1)
    Insert Into Asset Values (36,'FDB-036','Desc36',13,1)

此致,

我们可以应用 LevelPath 来尝试获取您的 child 计数,但仅显示 children 的第一级。我们最终通过路径对资产的计数进行分组,这是 children 第一层的 ID。那么select最后只有第一关

DECLARE @LocationID INT = 1;

WITH recursiveCTE AS
(
    SELECT 
        *,
        1 AS [Level],
        Id [Path]
    FROM 
        location l
    WHERE 
        l.ParentLocationId = @LocationID
    UNION ALL 
    SELECT 
        l.*,
        [Level] + 1,
        [Path]
    FROM 
        location l
        JOIN recursiveCTE r ON l.ParentLocationId = r.Id
),
countCte AS (
    SELECT 
        [Path] Id,
        COUNT(a.AssetNo) Qty
    FROM recursiveCTE c
    JOIN Asset a ON c.Id = a.CurrentLocationId 
    GROUP BY [Path]
)

SELECT  r.Id,
        r.[Name], 
        COALESCE(c.Qty,0) Qty 
FROM    recursiveCTE r
        LEFT JOIN countCte c ON r.Id = c.Id
WHERE   r.[Level] = 1;