SQL 层次结构 - 解析给定节点的所有祖先的完整路径

2024-05-06

我有一个由邻接列表描述的层次结构。不一定有单个根元素,但我确实有数据来识别层次结构中的叶(终端)项。所以,一个看起来像这样的层次结构......

1
- 2
- - 4
- - - 7
- 3
- - 5
- - 6 
8
- 9

...将通过表格来描述,就像这样。NOTE: 我没有能力改变这种格式。

id  parentid isleaf
--- -------- ------
1   null     0
2   1        0
3   1        0
4   2        0
5   3        1
6   3        1
7   4        1
8   null     0
9   8        1

这是示例表定义和数据:

CREATE TABLE [dbo].[HiearchyTest](
    [id] [int] NOT NULL,
    [parentid] [int] NULL,
    [isleaf] [bit] NOT NULL
)
GO

INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (1, NULL, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (2, 1, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (3, 1, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (4, 2, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (5, 3, 1)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (6, 3, 1)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (7, 4, 1)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (8, NULL, 0)
INSERT [dbo].[HiearchyTest] ([id], [parentid], [isleaf]) VALUES (9, 8, 1)
GO

由此,我需要提供任何 id 并获取所有祖先的列表,包括每个祖先的所有后代。所以,如果我提供的输入id = 6,我期望以下内容:

id descendentid
-- ------------
1  1
1  3
1  6
3  3
3  6
6  6
  • id 6 只有它自己
  • 它的父代 id 3 将有 3 和 6 的后代
  • 它的父代 id 1 将有 1、3 和 6 的后代

我将使用这些数据来提供层次结构中每个级别的汇总计算。假设我可以获得上面的数据集,这效果很好。

我使用两个递归 ctes 完成了这一任务 - 一个用于获取层次结构中每个节点的“终端”项。然后,在第二个步骤中,我获得所选节点的完整祖先(因此,6 解析为 6、3、1),然后向上走并获得完整的集合。我希望我遗漏了一些东西,并且这可以在一轮内完成。这是双递归代码示例:

declare @test int = 6;

with cte as (

    -- leaf nodes
    select id, parentid, id as terminalid
    from HiearchyTest
    where isleaf = 1

    union all

    -- walk up - preserve "terminal" item for all levels
    select h.id, h.parentid, c.terminalid
    from HiearchyTest as h
    inner join
    cte as c on h.id = c.parentid

)

, cte2 as (

    -- get all ancestors of our test value
    select id, parentid, id as descendentid
    from cte
    where terminalid = @test 

    union all

    -- and walkup from each to complete the set
    select h.id, h.parentid, c.descendentid
    from HiearchyTest h
    inner join cte2 as c on h.id = c.parentid

)

-- final selection - order by is just for readability of this example
select id, descendentid 
from cte2
order by id, descendentid

附加细节:“真实”层次结构将比示例大得多。从技术上讲,它可以具有无限深度,但实际上它很少会超过 10 层深度。

总之,我的问题是我是否可以使用单个递归 cte 来完成此任务,而不必在层次结构上递归两次。


因为你的数据是树形结构,所以我们可以使用hierarchyid数据类型来满足你的需求(尽管你在评论中说不能)。首先,简单的部分 - 使用递归 cte 生成 Hierarchyid

with cte as (

    select id, parentid, 
       cast(concat('/', id, '/') as varchar(max)) as [path]
    from [dbo].[HiearchyTest]
    where ParentID is null

    union all

    select child.id, child.parentid, 
       cast(concat(parent.[path], child.id, '/') as varchar(max))
    from [dbo].[HiearchyTest] as child
    join cte as parent
        on child.parentid = parent.id
)
select id, parentid, cast([path] as hierarchyid) as [path] 
into h
from cte;

接下来,我编写了一个小表值函数:

create function dbo.GetAllAncestors(@h hierarchyid, @ReturnSelf bit)
returns table
as return
   select @h.GetAncestor(n.n) as h
   from dbo.Numbers as n
   where n.n <= @h.GetLevel()
      or (@ReturnSelf = 1 and n.n = 0)

   union all

   select @h
   where @ReturnSelf = 1;

有了这些,获得你想要的结果集也不算太糟糕:

declare @h hierarchyid;

set @h = (
    select path
    from h
    where id = 6
);

with cte as (
    select * 
    from h
    where [path].IsDescendantOf(@h) = 1
        or @h.IsDescendantOf([path]) = 1
)
select h.id as parent, c.id as descendentid
from cte as c
cross apply dbo.GetAllAncestors([path], 1) as a
join h
    on a.h = h.[path]
order by h.id, c.id;

当然,如果不保留它,您就会错过使用 hierarchyid 的很多好处(您要么必须在边表中保持它最新,要么每次都生成它)。但就这样吧。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQL 层次结构 - 解析给定节点的所有祖先的完整路径 的相关文章

  • 使用 JSON 参数的 Postgres 批量 INSERT 函数

    这是一个plpgsqlpostgres 的函数9 6 它试图INSERT一行 如果插入没有失败 由于违反键约束 那么它会运行更多命令 CREATE FUNCTION foo int text text RETURNS void AS BEG
  • 插入触发器最终在分区表中插入重复行

    我有一个分区表 我认为 适当的INSERT触发器和一些限制 不知何故 INSERT语句为每个语句插入 2 行INSERT 一个用于父分区 一个用于相应的分区 设置简要如下 CREATE TABLE foo id SERIAL NOT NUL
  • Mysql 中 UNION 子句的替代方案

    我有两张桌子 表 a 表 b table a ID 1 2 3 4 5 7 table b ID 2 3 4 5 6 我必须得到这样的输出而无需UNION命令 ID 1 2 3 4 5 6 7 注意 我有一个联合解决方案 select fr
  • 了解 SSMS 2008 中关系的更新和删除规则

    当我们定义外键约束时 我对 SQL Server 2008 Management Studio 中的更新和删除规则的含义感到困惑 我也没有找到相关的帮助文档 例如F1帮助 这是屏幕快照 如果有人能描述它们的含义并推荐一些相关文档来阅读 我将
  • Amazon RDS for SQL Server 是否支持 SSIS?

    从谷歌搜索中读到一些相互矛盾的答案 不确定答案是是 否还是可能 我觉得读的时候已经很清楚了this http docs aws amazon com AmazonRDS latest UserGuide CHAP SQLServer htm
  • 使用 ADODB 连接从关闭的工作簿中检索数据。某些数据被跳过?

    我目前正在编写一些代码 可以通过 ADODB 连接访问单独的工作簿 由于速度的原因 我选择了这种方法而不是其他方法 下面是我的代码 Sub GetWorksheetData strSourceFile As String strSQL As
  • 初级SQL部分:避免重复表达式

    我对 SQL 完全陌生 但我们可以说StackExchange 数据浏览器 https data stackexchange com 我只想按信誉列出前 15 位用户 我写了这样的内容 SELECT TOP 15 DisplayName I
  • MySQL 查询到 CSV [重复]

    这个问题在这里已经有答案了 有没有一种简单的方法来运行MySQL查询来自linux命令行并以csv格式输出结果 这就是我现在正在做的事情 mysql u uid ppwd D dbname lt lt EOQ sed e s g tee l
  • 实体框架 - SQL Server 2005 - IIS 服务器日期时间问题

    我正在使用 MVC3 和实体框架 在我的应用程序中 我需要通过 EF 调用 SQL Server 2005 中的存储过程来根据以下内容搜索一些数据datetime传递的参数 在当地环境中一切似乎都运行良好 但是将其托管到 IIS 后 我在尝
  • SELECT 语句会受到 SQL 注入攻击吗?

    实际上有2个问题 我知道我必须尽可能多地使用存储过程 但我想知道以下内容 A 我可以从 SELECT 语句 例如 Select from MyTable 获得 SQL 注入攻击吗 B 另外 当我在 ASP NET 中使用 SQLDataSo
  • 为表中的每个组选择前 N 行

    我面临一个非常常见的问题 即 为表中的每个组选择前 N 行 考虑一个表id name hair colour score列 我想要一个结果集 对于每种头发颜色 都能得到前 3 名得分手的名字 为了解决这个问题 我得到了我所需要的Rick O
  • SQL Server 列名区分大小写

    我使用的数据库具有 French CI AS 排序规则 CI 应该代表不区分大小写 但无论如何都是区分大小写的 我试图理解为什么 我断言这一点的原因是 使用 GIVEN 案例设置进行批量插入失败 但使用另一个 Given 案例设置则成功 例
  • 如何使用sql作为xml路径('')但保留回车符

    我有下面的代码 select select cast Narrative as Varchar max char 13 from officeclientledger where ptmatter matter and ptTrans 4
  • 将表数据从一个 SQL Server 导出到另一台 SQL Server

    我有两个 SQL Server 都是 2005 版本 我想将多个表从一个表迁移到另一个表 我努力了 在源服务器上 我右键单击数据库 选择Tasks Generate scripts 问题是在下面Table View options没有Scr
  • SQL不允许表中有重复记录

    如何使其不添加重复项 我想让它通过 ID 之外的所有其他列进行检查 我希望这个无效 ID col1 col2 col3 1 first middle last ID col1 col2 col3 2 first middle last 我希
  • 如何在NiFi中映射流文件中的列数据?

    我有 csv 文件 其结构如下 Alfreds Centro Ernst Island Bacchus Germany Mexico Austria UK Canada 01 02 03 04 05 现在我必须将这些数据移入数据库 如下所示
  • SQL - != 'NULL' 的解释

    我的SSMS代码如下 Select top 50 From FilteredContact Where statuscode 1 and emailaddress1 NULL and telephone1 NULL and address1
  • 可以获取SQL Server中当前执行的存储过程的行号吗?

    几年前 我在 Sybase Delphi 环境中工作 使用 BDE 连接到数据库服务器 我们有一个 Delphi 小应用程序 给定当前正在执行的存储过程的名称 它可以告诉您当前正在执行该存储过程的哪一行 这对于调试似乎挂起的存储过程非常有用
  • 如何跨多个表强制执行 CHECK 约束

    我有一个在 Microsoft SQL Server 2012 Express 中记录奶牛繁殖信息的数据库 显然 一头牛只有在出生后才能配种 并且在其一生中可能会配种多次 我需要在我的数据库中强制执行这些约束 我目前已经根据下图安排了一个架
  • 如何修改现有表以添加时区

    我有一个包含 500 多个表的大型应用程序 我必须将应用程序转换为时区感知 当前应用程序使用new java util Date GETDATE 与服务器的时区 即没有任何时区支持 我已将这项任务分为几个步骤 以便于开发 我确定的第一个步骤

随机推荐

  • 如何在模板形式 Angular 2 中使用最小、最大验证[重复]

    这个问题在这里已经有答案了 我尝试在模板表单中使用 min 验证 但它不起作用 如何以模板形式使用它 感谢您的帮助
  • 启动时启动服务但不进行任何活动

    我想创建一个仅包含服务 无活动 的应用程序 该服务必须在启动时启动 我的问题是 如果没有活动 启动接收器似乎不会调用 我用下面的例子进行了测试 我有不同的文件 MyReceiver java package com test teststa
  • Android 谷歌地图圆圈平滑改变半径

    我想控制按进度条循环 但是谷歌地图APIsetRadius变化并不顺利 如何平滑改变圆半径 这是我的源代码 private Circle circle public void onMapReady final GoogleMap googl
  • 在 bash 函数中生成后台进程

    我正在编写一个 Bash 函数来启动需要从某个文件夹启动的服务器 但我不希望启动该服务器影响我当前的工作 我写了以下内容 function startsrv pushd cd TRUNK SERVERCOMMAND popd 我的变量都已设
  • Django:如何从管理界面调用管理自定义命令执行?

    参考 从代码执行管理命令 https stackoverflow com questions 907506 how can i call a custom django manage py command directly from a t
  • 如何在 TFS 2015 中链接构建?

    TFS 2015 中是否有一种方法可以进行两个构建 以便每当第一个构建 成功 完成时就会触发第二个构建 那里are https tfschainbuild codeplex com 解决方案 https blog stangroome co
  • SET IDENTITY_INSERT [表] ON 不起作用

    我想在指定 Id 的位置插入一些记录 以便将数据迁移到我想要保持现有关系完整性的位置 为此 我直接在 SSMS 中的表上运行以下命令 SET IDENTITY INSERT CRMTItem ON 然而 当我从 C 插入一个 Id 为 1
  • 调整大小时标题不响应

    我有一个表格 当我调整大小时它不会显示我的标题Steps在网络视图上 它确实显示得很完美 但是当我调整大小时 我看不到我的步骤标题 有没有办法使用 css 或 jstl jsf 标签在下面的代码中修复此问题 谢谢您的帮助 像这样的事情 ht
  • 如何使用 Java 在 Android Wi-Fi 连接上设置 ProxySettings 和 ProxyProperties?

    如何使用 Java 以编程方式 在 Android Wi Fi 连接上设置 ProxySettings 和 ProxyProperties 由于 ipAssignment linkProperties ProxySettings 和 Pro
  • Grails - 错误分叉 Grails VM 因错误退出

    首先 我想说 我是 Grails 的初学者 在尝试遵循一些示例时 我不断收到无法解决的错误 如果问题很愚蠢 那么很抱歉 我通过命令行创建了一个虚拟应用程序 并尝试以相同的方式运行它 run app 但出现以下错误 运行 Grails 应用程
  • XSL:让原始 HTML 通过

    我正在进行 XSL 转换 我正在转换的 XML 有一个包含 html 的节点
  • 如何更改Android布局中XML片段元素的默认提示值

    默认提示值自动完成 https developers google com places android api autocomplete小部件是Search 如何将该值更改为不同的值String 尝试下面的代码 PlaceAutocomp
  • matlab矩阵中求子矩阵的通用方法

    我正在寻找一种 好 方法来在更大的矩阵 任意维数 中找到矩阵 模式 Example total rand 3 4 5 sub total 2 3 1 3 3 4 现在我希望这样的事情发生 loc matrixFind total sub 在
  • UIView 动画选项重复计数

    我的 Swift 代码遇到一些问题 我试图使 UIImageView 对象消失并重新出现一次 但在让动画仅播放一次方面遇到一些问题 IBOutlet weak var ball UIImageView IBAction func onFad
  • 复制构造函数和移动构造函数的效率差异

    C 11引入了右值引用的新概念 我在某处读到它并发现以下内容 class Base public Base Default Ctor Base int t Parameterized Ctor Base const Base b Copy
  • JQUERY MOBILE 文本输入中的自动完成

    我在网上搜索了很多但找不到任何解决方案 我正在制作一个网络应用程序 其中我想要 2 个文本框来获取用户的数据输入 我想要此文本框中的自动完成功能 自动完成的标签列表在本地可用 我尝试了listview 但我想要的是 在用户从自动完成提示中选
  • C# - 检索 COM+ 组件的属性?

    我的服务器 Windows Server 2003 上有一个 COM 组件 有什么方法可以以编程方式检索该组件的属性 例如使用的构造函数字符串 当我转到管理工具 gt 组件服务 gt COM 应用程序并右键单击我的组件时 这些是我希望能够检
  • 如何在使用应用程序的用户之间获得 Facebook 相互点赞

    假设两个用户正在使用一个应用程序 并已授予该应用程序适当的权限来检索他们的喜好 是否可以使用 FQL 或图形 API 来查找它们的共同点 类似于如何使用图形 API 查找两个用户之间的共同好友 我认为在我浏览文档时不存在这样的 api 调用
  • 手电筒打开时 Android 相机的奇怪行为

    我有以下 android 代码 这里用伪代码编写 mCamera configAndInitialize all I want to do before taking picture mCamera startPreview mCamera
  • SQL 层次结构 - 解析给定节点的所有祖先的完整路径

    我有一个由邻接列表描述的层次结构 不一定有单个根元素 但我确实有数据来识别层次结构中的叶 终端 项 所以 一个看起来像这样的层次结构 1 2 4 7 3 5 6 8 9 将通过表格来描述 就像这样 NOTE 我没有能力改变这种格式 id p