【问题标题】:Select all hierarchy level and below SQL Server选择 SQL Server 及以下的所有层次结构级别
【发布时间】:2016-04-22 03:18:40
【问题描述】:

我在这个问题上遇到了困难。我已经看到了一些关于如何从给定父项的自引用表中获取所有子记录的示例,甚至如何获取子记录的父项。

我要做的是返回一条记录以及给定 ID 的所有子记录。

为了说明这一点 - 我有一个公司层次结构。地点:

#Role        Level#
--------------------
Corporate         0
Region            1
District          2
Rep               3

我需要的是一个过程,(1) 确定记录的级别,(2) 检索该记录和所有子记录。

作为一个地区的想法可以看到一个地区的所有地区和代表,地区可以看到他们的代表。代表只能看到自己。

我有桌子:

ID            ParentId           Name
-------------------------------------------------------
1             Null               Corporate HQ
2             1                  South Region
3             1                  North Region
4             1                  East Region
5             1                  West Region
6             3                  Chicago District
7             3                  Milwaukee District
8             3                  Minneapolis District
9             6                  Gold Coast Dealer
10            6                  Blue Island Dealer

我该怎么做:

CREATE PROCEDURE GetPositions
    @id int
AS
BEGIN
    --What is the most efficient way to do this--
END
GO

例如@id = 3 的预期结果,我想返回:

3, 6, 7, 8, 9, 10

如果有任何帮助或想法,我将不胜感激。

【问题讨论】:

  • 预期的结果是什么?
  • 我更新了问题以显示预期结果。

标签: sql sql-server stored-procedures


【解决方案1】:

您可以通过递归 CTE 做到这一点:

DECLARE @id INT = 3;

WITH rCTE AS(
    SELECT *, 0 AS Level FROM tbl WHERE Id = @id
    UNION ALL
    SELECT t.*, r.Level + 1 AS Level
    FROM tbl t
    INNER JOIN rCTE r
        ON t.ParentId = r.ID
)
SELECT * FROM rCTE OPTION(MAXRECURSION 0);

ONLINE DEMO

【讨论】:

  • 太完美了!只是出于好奇-这对大量记录是否会表现良好。 IE。假设我有 50K + 记录,并且 Id 是公司(顶级)父级。这将如何维持?
  • 一般来说,递归 CTE 在大型表上不能很好地扩展。和所有东西一样,测试!
【解决方案2】:

假设您使用的是相当现代的 SQL Server 版本,您可以稍微费点力气地使用 hierarchyid 数据类型。一、设置:

alter table [dbo].[yourTable] add [path] hierarchyid null;

接下来,我们将填充新列:

with cte as (
   select *, cast(concat('/', ID, '/') as varchar(max)) as [path]
   from [dbo].[yourTable]
   where [ParentID] is null

   union all

   select child.*, 
      cast(concat(parent.path, child.ID, '/') as varchar(max)) as [path]
   from [dbo].[yourTable] as child
   join cte as parent
      on child.ParentID = parent.ID
)
update t
set path = c.path
from [dbo].[yourTable] as t
join cte as c
   on t.ID = c.ID;

这只是一个沼泽标准递归表表达式,其中一个计算列表示层次结构。那是困难的部分。现在,您的程序可能如下所示:

create procedure dbo.GetPositions ( @id int ) as
begin
   declare @h hierarchyid
   set @h = (select Path from [dbo].[yourTable] where ID = @id);

   select ID, ParentID, Name
   from [dbo].[yourTable]
   where Path.IsDescendentOf(@h) = 1;
end

因此,总而言之,您对 hierarchyid 所做的一切就是存储给定行的沿袭,这样您就不必在选择时即时计算它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    • 1970-01-01
    • 2016-02-02
    • 1970-01-01
    • 2019-08-10
    相关资源
    最近更新 更多