在父组件下将所有组件返回多个级别

时间:2019-05-09 07:21:58

标签: sql sql-server hierarchy hierarchical-data

我有一个分层数据库,我想从中返回具有特定通用父组件的资产中的所有组件。

astComponents中的组件通过引用其他组件ParentComponentId的{​​{1}}链接到其父组件。但是,这仅将父级显示一级。

此外,所有组件都通过Id键链接到资产,并链接到表AssetId中的Id键。

我能够进行一个简单的查询(如下),以从特定资产中检索所有组件。我无法弄清楚如何从共享同一父组件的特定资产中返回所有组件。此父级组件(相对于子级组件)可以向上一级升级。

astAssets

上面的查询将组件及其父级返回一级。如果我指定父代码,它将仅将子组件返回到此指定组件下一级的子组件,而不是返回所有下一级的子组件。

2 个答案:

答案 0 :(得分:1)

好的,没有任何可用的数据,这里有很多猜测。我创建了一些数据:

ComboBox

您可以执行以下操作:使用递归来映射共享同一父级的所有组件,并记录它们属于哪个资产,例如:

DECLARE @astComponents TABLE (Id INT, Code VARCHAR(50), ParentComponentId INT, AssetId INT);
DECLARE @astAssets TABLE (Id INT, Code VARCHAR(50));
INSERT INTO @astAssets SELECT 1, '2018100000';
INSERT INTO @astAssets SELECT 2, '2018100001';
INSERT INTO @astComponents SELECT 1, 'Power Supply', NULL, 1;
INSERT INTO @astComponents SELECT 2, 'Fan', 1, NULL;
INSERT INTO @astComponents SELECT 3, 'Screw', 2, NULL;
INSERT INTO @astComponents SELECT 4, 'Heat Tape', 1, NULL;
INSERT INTO @astComponents SELECT 5, 'Magnet', NULL, 2;
INSERT INTO @astComponents SELECT 6, 'Iron', 5, NULL;

我敢打赌,您的桌子不能像这样工作,因此您需要对其进行调整以适应需要。就我而言,我得到以下结果:

--Make a recursive list of components sharing a common parent
WITH cte AS (
    SELECT
        Id,
        ParentComponentId,
        AssetId
    FROM
        @astComponents
    WHERE
        ParentComponentId IS NULL
    UNION ALL
    SELECT
        c.Id,
        c.ParentComponentId,
        cte.AssetId
    FROM
        @astComponents c
        INNER JOIN cte ON cte.Id = c.ParentComponentId)
SELECT * FROM cte;

因此,我可以看到组件#1和#5没有父级,因此它们是“顶级”组件,并且我还可以看到哪些组件链接到哪些资产。

现在仅是将查询的Id ParentComponentId AssetId 1 NULL 1 5 NULL 2 6 5 2 2 1 1 4 1 1 3 2 1 部分替换为这样的情况:

SELECT * FROM cte

为我提供了共享父级的所有组件,其中父级的资产代码为201810000:

SELECT 
    cte.Id,
    c.Code,
    c.ParentComponentId
FROM 
    cte
    INNER JOIN @astComponents c ON c.Id = cte.Id
    INNER JOIN @astAssets a ON a.Id = cte.AssetId
WHERE
    a.Code = '2018100000';

答案 1 :(得分:0)

因此,如果我正确理解了这一点,则您有一个已知的父组件,一个已知的资产代码。您想使用它们来构建一棵树,覆盖从父级组件到所讨论资产的路径(由于缺少更好的词)?

这是一种尝试。我们首先构建一些用于测试的伪数据:

declare @component table (
    id int primary key,
    code nvarchar(50) not null,
    parent_id int null,
    asset_id int null
)
declare @asset table (
    id int primary key,
    code nvarchar(50)
)

insert into @asset values (1, '2018100000')
insert into @asset values (2, '2019100000')

insert into @component values(1, 'root', null, null)
insert into @component values(2, 'c1', 1, null)
insert into @component values(3, 'c2', 1, null)
insert into @component values(4, 'c3', 1, null)
insert into @component values(5, 'c2_c1', 3, null)
insert into @component values(6, 'c2_c2', 3, 1)
insert into @component values(7, 'c2_c1_c1', 5, 2)
insert into @component values(8, 'c2_c1_c2', 5, 1)
insert into @component values(9, 'c2_c1_c2_c1', 8, 2)
insert into @component values(9, 'c2_c1_c1_c1', 7, 1)

然后,我们声明几个递归CTE:s并将其用于获取输出:

declare @specParentId int
declare @assetCode nvarchar(50)
set @specParentId = 3
set @assetCode = '2018100000'

;with compRecurseDown as (
    select c.id, c.code, parent_id, 0 as level, c.asset_id
    from @component c
    where c.id = @specParentId

    union all

    select c.id, c.code, c.parent_id, p.level + 1, c.asset_id
    from @component c
        join compRecurseDown p on c.parent_id = p.id
), assetRecurseUp as (
    select c.*
    from @asset a
        join @component c on a.id = c.asset_id
    where a.code = @assetCode

    union all 

    select c.*
    from @component c
        join assetRecurseUp p on p.parent_id = c.id
)
select crd.*, a.code as asset_code
from compRecurseDown crd
    left outer join @asset a on crd.asset_id = a.id
where crd.id in (
    select id from assetRecurseUp
)
order by level

在这种情况下,我们正在ID为2018100000的组件下寻找资产3。结果:

| id | code     | parent_id | level | asset_id | asset_code | 
|----|----------|-----------|-------|----------|------------| 
| 3  | c2       | 1         | 0     | NULL     | NULL       | 
| 5  | c2_c1    | 3         | 1     | NULL     | NULL       | 
| 6  | c2_c2    | 3         | 1     | 1        | 2018100000 | 
| 8  | c2_c1_c2 | 5         | 2     | 1        | 2018100000 | 

那么这如何工作?首先,我们声明compRecurseDown CTE。它使用已知的父组件作为其anchor,然后递归地找到该节点下的所有子注释。

assetRecurseUp CTE首先找到链接到已知资产的所有组件。然后,基于此递归添加所有父节点。

最后,我们查询这两者的组合以产生最终结果集。