如何从 Microsoft SQL Server 表中获取/搜索大量行且具有多个级别的分层数据?

问题描述 投票:0回答:2

我在 Microsoft SQL Server 中有一个表,其中包含一些列,它还包含 2 列用于分层数据。层次结构可以非常深,例如超过 15 级,并且表中可以有大量行。表结构是像下面这样:

表名称:tbl1

col_a(vachar)    col_b(varchar)    col_c(varchar)  col_d(varchar) ....more columns
----------------------------------------------------------------------------------
12              16               Japan           3
16              17               Australia       2
17               0               Panama          1
19              12               CostaRica       4
22              16               Brazil          3
11              12               Bhutan          4
14              17               Japan           2
....more rows

如果为此构建一棵树,它将如下所示:

17 (Panama)
|
|__16  (Australia)
|   |
|   |__12 (Japan)
|   |  |
|   |  |__ 19 (CostaRica)
|   |  |
|   |  |__11 (Bhutan)
|   |
|   |__22 (Brazil)
|
|__14 (Japan)

现在如果我搜索日本,我应该会看到以下内容

17 (Panama)
|
|__16 (Australia)
|   |
|   |__ 12(Japan)
|
|__14(Japan)

col_a
包含每行的 id 值,
col_b
包含每行的父 id 值。

例如。上面的行中 17 是第一个节点(预定义为第一个节点的 id 为 17,我不需要检查 17 是否有父节点),16 和 14 是 17 的子节点。然后 12 和22 是 16 的子节点,依此类推。

col_c
有一些文本(此处给出国家/地区名称是出于例如目的)。
col_d
有级别值。

我需要以树格式显示分层数据。还必须在树上实现搜索。

我尝试了两种显示树结构的方法。我可以显示树,但无法实现搜索。

现在我首先尝试从存储过程中获取 XML 格式的数据,然后将该 XML 转换为 JSON(我的 SQL Server 版本不支持

FOR JSON PATH
,但它支持
FOR XML PATH
)。因此,我尝试获取整个树 JSON 并使用 Angular 的 Ng Prime 树组件来显示/搜索树。

为此,我在 SQL Server 中尝试了以下方法:

WITH cte1 AS
( 
    SELECT col_a, col_b, col_c, col_d
    FROM tbl1 
    WHERE col_a = '17'
), cte2 AS
(
    SELECT col_a, col_b, col_c, col_d
    FROM tbl1 AS t 
    WHERE t.col_b IN (SELCET col_a FROM cte1)
),
cte3 AS
(
    SELECT col_a, col_b, col_c, col_d
    FROM tbl1 AS t 
    WHERE t.col_b IN (SELECT col_a FROM cte2)
)
SELECT
    cte1.col_a, cte1.col_b, cte1.col_c, cte1.col_d,
    cte2.col_a, cte2.col_b, cte2.col_c, cte2.col_d,
    cte3.col_a, cte3.col_b, cte3.col_c, cte3.col_d
FROM
    cte1
LEFT JOIN
    cte2 ON cte2.col_b = cte1.col_a
LEFT JOIN
    cte3 ON cte3.colb = cte2.col_a;

由于我们不知道层次结构可以有多深,所以我从表中获取了最大级别并将上述查询构建为字符串,然后使用

sp_executesql
运行它。这种方法是有效的,但当数据大小和层次结构深度非常大时,它就会失败。

我也尝试过递归 CTE,但由于相同的大量行和大深度,这也不起作用。

因此,由于无法一次获取整个树数据,我尝试了不同的方法。

在第二种方法中,我没有使用任何库中的任何组件,并且我以角度构建了一个简单的组件,它将显示分层列表。在此列表中,我首先仅显示节点 17,当用户单击节点 17 时,我调用 API 控制器,该控制器又调用存储过程来获取父级为 17 的所有节点,即节点 16 和 14。

然后,当用户单击节点 16 时,将返回并显示父节点为 16 的节点,即 12 和 22。这工作正常,我已经使用这种方法做了一些工作。但现在的问题是搜索。我不知道如何以上述格式显示搜索结果。当用户搜索文本(例如日本)时,我应该如何获取并显示数据(请参阅上面给出的搜索)?

sql-server tree hierarchy
2个回答
0
投票

嗯,对于 CTE,我会选择这样的东西:

;with data as (
    select *
    from (
        VALUES(12,              16          ,N'Japan'           ,3)
        ,(16,              17               ,N'Australia'       ,2)
        ,(17,               0               ,N'Panama'          ,1)
        ,(19,              12               ,N'CostaRica'       ,4)
        ,(22,              16               ,N'Brazil'          ,3)
        ,(11,              12               ,N'Bhutan'          ,4)
        ,(14,              17               ,N'Japan'           ,2)
    ) a(id, parent, name,x)
    )
,   hierarchy as (
    SELECT  id, CAST(id AS NVARCHAR(MAX)) + '_' AS path, name, name AS name2, 0 level, parent
    FROM    data d
    where parent > 0
    
    UNION ALL
    SELECT  d.id, h.path +  CAST(d.id AS NVARCHAR(MAX)) + '_' AS path, h.name, d.name, h.level + 1, d.parent
    FROM    data d
    INNER JOIN hierarchy h
        ON  h.parent = d.id
)
select REPLICATE('|_', level) + name2, path, id, parent,name, name2
from hierarchy
--where name = 'japan'
order by path

;with data as (
    select *
    from (
        VALUES(12,              16          ,N'Japan'           ,3)
        ,(16,              17               ,N'Australia'       ,2)
        ,(17,               0               ,N'Panama'          ,1)
        ,(19,              12               ,N'CostaRica'       ,4)
        ,(22,              16               ,N'Brazil'          ,3)
        ,(11,              12               ,N'Bhutan'          ,4)
        ,(14,              17               ,N'Japan'           ,2)
    ) a(id, parent, name,x)
    )
,   hierarchy as (
    SELECT  id, CAST(id AS NVARCHAR(MAX)) + '_' AS path, name, 0 level
    FROM    data
    WHERE   parent = 0
    UNION ALL
    SELECT  d.id, h.path +  CAST(d.id AS NVARCHAR(MAX)) + '_' AS path, d.name, h.level + 1
    FROM    data d
    INNER JOIN hierarchy h
        ON  h.id = d.parent
)
select REPLICATE('|_', level) + name, path, id
from hierarchy
order by path

第一个是数据的“以元素为中心”视图,即。它跟踪每个元素的父元素,它在搜索或类似的事情中可能很有用。

第二个是定期查看数据。如果正确索引“parent”和“id”,则获取不会太慢。但话虽如此,加载它后,您应该将其保留在内存中而不是访问数据库。

路径可以用作标识符和树构建块


0
投票

首先,MS SQL Server 中有一个专用的数据类型来执行此操作。 HierarchyId 与许多操作树结构的方法相关联...

阅读:hierarchyid 数据类型方法参考

但是我处理树的首选方法是将经典的邻接表转换为嵌套区间......

了解此方法:嵌套集合模型

© www.soinside.com 2019 - 2024. All rights reserved.