从父子表生成字符串树分支

2024-01-02

我有一个父子表,如下所示:

child   |   father
H       :   G
F       :   G
G       :   D
E       :   D
A       :   E
B       :   C
C       :   E

我希望 sql server 生成类似的东西(正如这个问题中所问的那样)将一系列父子关系转化为层次树? https://stackoverflow.com/questions/2915748/how-can-i-convert-a-series-of-parent-child-relationships-into-a-hierarchical-tre但在 sql 中而不是在 php 中):

 D
 ├── E
 │   ├── C
 │   │   └── B
 │   └── A   
 └── G
     ├── F
     └── H

当然,结果可以是一个字符串列,我可以在文本编辑器中复制它。

我还希望有第二个查询来生成如下内容:

 father |   descendants
 D      |   D -> E -> C -> B
 D      |   D -> E -> A
 D      |   D -> G -> F
 D      |   D -> G -> H

在前一种情况下,只有一棵树有一个父亲,但在表中可能有更多的树有多个父亲,就像如果 D 不存在时这棵树一样。

如果请求的第一部分(伪视觉树)无法完成,也可以。重要的部分是桌子。

我已经尝试做这样的事情很长时间了,但我无法达到想要的结果。

TNX


这很有趣。不过,使用 SQL 而不是其他语言可能效率较低。想起来还是很有趣的。

我是这样做的。

初始化表:

SET NOCOUNT ON
DECLARE @Table TABLE ([Child] NVARCHAR(10), [Parent] NVARCHAR(10))
INSERT @Table VALUES ('H','G'),('F','G'),('G','D'),('E','D')
,('A','E'),('B','C'),('C','E'),('D', NULL),('Z','E'),('X','Z'),('Y','Z')
,('L',NULL),('M','L'),('N','L'),('P','N'),('Q','L'), ('R',NULL),('S', 'R')
IF OBJECT_ID('tempdb..#tmptable') IS NOT NULL DROP TABLE #tmptable
; WITH T AS (
    SELECT Parent, Child, 1 [Level]
    FROM @Table
    WHERE Parent IS NULL
    UNION ALL
    SELECT a.Parent, a.Child, T.[Level] + 1
    FROM @Table a
    JOIN T ON a.Parent = T.Child)
SELECT *
INTO #tmptable
FROM T

对于查询 1,我使用动态 SQL,假设您不知道任何给定父级可以拥有的最大后代数量:

DECLARE @SQL NVARCHAR(MAX)
DECLARE @a INT = (SELECT MAX(Level) FROM #tmptable)
DECLARE @b INT = 2
SET @SQL = 
'; WITH CTE AS (
    SELECT T1.Child Father'
WHILE @b<= @a BEGIN
    SET @SQL += '
        , ISNULL(T' + CONVERT(NVARCHAR, @b) + '.Child, '''') Child' + CONVERT(NVARCHAR, @b - 1)
    SET @b += 1
END
SET @SQL +='
        , ROW_NUMBER() OVER (ORDER BY T1.Child'
SET @b =  2 
WHILE @b <= @a BEGIN        
    SET @SQL += ', T' + CONVERT(NVARCHAR, @b) + '.Child'
    SET @b += 1
END
SET @SQL += ') RN
    FROM #tmptable T1'
SET @b = 2
WHILE @b <= @a BEGIN
    SET @SQL += '
    LEFT JOIN #tmptable T' + CONVERT(NVARCHAR, @b) + ' ON T' + CONVERT(NVARCHAR, @b) +'.Parent = T' + CONVERT(NVARCHAR, @b - 1) + '.Child'
    SET @b += 1
END
SET @SQL += '
    WHERE T1.Parent IS NULL
    GROUP BY T1.Child'
SET @b = 2
WHILE @b <= @a BEGIN
    SET @SQL += ', T' + CONVERT(NVARCHAR, @b) + '.Child'
    SET @b += 1
END
SET @SQL += ')
SELECT ''<ul>'' + REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), (
    SELECT CASE WHEN RN = 1 THEN ''<li>''
            WHEN (SELECT Father FROM CTE WHERE RN = C.RN - 1) <> Father THEN ''<li>''
            ELSE '''' END --Fatherli
        , CASE WHEN RN = 1 THEN Father
            WHEN (SELECT Father FROM CTE WHERE RN = C.RN - 1) <> Father THEN Father
            ELSE '''' END --Father
        , CASE WHEN RN = 1 THEN ''</li>''
            WHEN (SELECT Father FROM CTE WHERE RN = C.RN - 1) <> Father THEN ''</li>''
            ELSE '''' END --Fathercli
        , CASE WHEN RN = 1 AND Child1 <> '''' THEN ''<ul>''
            WHEN (SELECT Father FROM CTE WHERE RN = C.RN - 1) <> Father AND Child1 <> '''' THEN ''<ul>''
            ELSE '''' END --Fatherul'
SET @b = 2
WHILE @b <= @a BEGIN
    SET @SQL += '
        , CASE WHEN RN = 1 AND Child' + CONVERT(NVARCHAR, @b-1) + ' <> '''' THEN ''<li>''
            WHEN (SELECT Child' + CONVERT(NVARCHAR, @b-1) + ' FROM CTE WHERE RN = C.RN - 1) <> Child' + CONVERT(NVARCHAR, @b-1) + ' AND Child' + CONVERT(NVARCHAR, @b-1) + ' <> '''' THEN ''<li>''
            ELSE '''' END --Child' + CONVERT(NVARCHAR, @b-1) + 'li
        , CASE WHEN RN = 1 AND Child' + CONVERT(NVARCHAR, @b-1) + ' <> '''' THEN Child' + CONVERT(NVARCHAR, @b-1) + '
            WHEN (SELECT Child' + CONVERT(NVARCHAR, @b-1) + ' FROM CTE WHERE RN = C.RN - 1) <> Child' + CONVERT(NVARCHAR, @b-1) + ' AND Child' + CONVERT(NVARCHAR, @b-1) + ' <> '''' THEN Child' + CONVERT(NVARCHAR, @b-1) + '
            ELSE '''' END --Child' + CONVERT(NVARCHAR, @b-1) + '
        , CASE WHEN RN = 1 AND Child' + CONVERT(NVARCHAR, @b-1) + ' <> '''' THEN ''</li>''
            WHEN (SELECT Child' + CONVERT(NVARCHAR, @b-1) + ' FROM CTE WHERE RN = C.RN - 1) <> Child' + CONVERT(NVARCHAR, @b-1) + ' AND Child' + CONVERT(NVARCHAR, @b-1) + ' <> '''' THEN ''</li>''
            ELSE '''' END --Child' + CONVERT(NVARCHAR, @b-1) + 'cli'
    IF @a <> @b 
        SET @SQL += '
        , CASE WHEN RN = 1 AND Child' + CONVERT(NVARCHAR, @b-1) + ' <> '''' AND Child' + CONVERT(NVARCHAR, @b) + ' <> '''' THEN ''<ul>''
            WHEN (SELECT Child' + CONVERT(NVARCHAR, @b-1) + ' FROM CTE WHERE RN = C.RN - 1) <> Child' + CONVERT(NVARCHAR, @b-1) + ' AND Child' + CONVERT(NVARCHAR, @b) + ' <> '''' THEN ''<ul>''
            ELSE '''' END --Child' + CONVERT(NVARCHAR, @b-1) + 'ul'
    SET @b += 1
END
SET @b -= 3
WHILE @b > 0 BEGIN
    SET @SQL += '
        , CASE WHEN RN = (SELECT MAX(RN) FROM CTE) AND Child' + CONVERT(NVARCHAR, @b+1) + ' <> '''' THEN ''</ul>''
            WHEN (SELECT Child' + CONVERT(NVARCHAR, @b) + ' FROM CTE WHERE RN = C.RN + 1) <> Child' + CONVERT(NVARCHAR, @b) + ' AND Child' + CONVERT(NVARCHAR, @b+1) + ' <> '''' THEN ''</ul>''
            ELSE '''' END --Child' + CONVERT(NVARCHAR, @b) + 'cul'
    SET @b -= 1
END
SET @SQL += '
        , CASE WHEN RN = (SELECT MAX(RN) FROM CTE) AND Child1 <> '''' THEN ''</ul>''
            WHEN (SELECT Father FROM CTE WHERE RN = C.RN + 1) <> Father AND Child1 <> '''' THEN ''</ul>''
            ELSE '''' END --Fathercul
    FROM CTE C
    FOR XML PATH (''''))), ''&lt;'', ''<''), ''&gt;'', ''>'') + ''</ul>'''
EXEC(@SQL)
-- PRINT @SQL

输出(对于我输入的值)是<ul><li>D</li><ul><li>E</li><ul><li>A</li><li>C</li><ul><li>B</li></ul><li>Z</li><ul><li>X</li><li>Y</li></ul></ul><li>G</li><ul><li>F</li><li>H</li></ul></ul><li>L</li><ul><li>M</li><li>N</li><ul><li>P</li></ul><li>Q</li></ul><li>R</li><ul><li>S</li></ul></ul>显示如下:

  • D
    • E
      • A
      • C
        • B
      • Z
        • X
        • Y
    • G
      • F
      • H
  • L
    • M
    • N
      • P
    • Q
  • R
    • S

对于第二个查询,可能有更简单的方法来完成它,但我想为什么不使用更动态的 SQL?

DECLARE @i INT = (SELECT MAX([Level]) FROM #tmptable), @j INT = 2
DECLARE @SQL2 NVARCHAR(MAX)
SET @SQL2 = 'SELECT T1.Child Father, T1.Child '
WHILE @j <= @i BEGIN
    SET @SQL2 += '+ ISNULL('' -> '' + T' + CONVERT(NVARCHAR, @j) + '.Child, '''')'
    SET @j += 1
END
SET @j = 2
SET @SQL2 += ' Descendants FROM #tmptable T1'
WHILE @j <= @i BEGIN
    SET @SQL2 += ' LEFT JOIN #tmptable T' + CONVERT(NVARCHAR, @j) + ' ON T' + CONVERT(NVARCHAR, @j) + '.[Parent] = T' + CONVERT(NVARCHAR, @j-1) + '.[Child]'
    SET @j += 1
END
SET @j = 2
SET @SQL2 += ' WHERE T1.[Parent] IS NULL ORDER BY T1.[Child]'
WHILE @j <= @i BEGIN
    SET @SQL2 += ', T' + CONVERT(NVARCHAR, @j) + '.[Child]'
    SET @j += 1
END
EXEC(@SQL2)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从父子表生成字符串树分支 的相关文章

随机推荐

  • ActiveJob::SerializationError - 不支持的参数类型:时间/日期时间

    我正在使用 Rails 5 和 ActiveJob 来处理后台任务 我正在尝试传递一个序列化的对象as json到我的工作 但我收到以下错误 ActiveJob SerializationError Unsupported argument
  • 如何将 Passport 和 Angular-UI 路由结合起来

    我想知道如何将 Angular UI Routing 与 Passport 结合起来 我找到的所有示例都使用 node js 路由 var routerApp angular module routerApp ui router route
  • 使用 json_modify.py 更改 JSON 键名称

    如何使用更改 JSON 键名称json 修改 py https github com integr8ly installation blob master library json modify py 我有以下数组 我想更改public i
  • System.Data.OracleClient 不适用于 64 位 Oracle 客户端

    我设计了一个 C 应用程序来连接到 Oracle 数据库并更改架构用户密码 我的参考程序集是来自以下位置的 System Data OracleClient C Program Files x86 Reference Assemblies
  • Rails 4 中的 has_many 'conditions' 选项相当于什么?

    有人能告诉我在 Rails 4 中执行以下行的等效方法是什么吗 has many friends through gt friendships conditions gt status accepted order gt first nam
  • MSBuild - 如何复制可能存在或不存在的文件?

    我遇到一种情况 我需要在 MSBuild 脚本中复制一些特定文件 但它们可能存在也可能不存在 如果它们不存在也没关系 我就不需要它们了 但标准
  • 在未知的 NSMutableArray 深度中搜索值

    好吧 我问了错误的问题 所以我编辑了原来的问题 我将数组存储在数组中 以及 NSDictionaries 它是一种实用程序类型的应用程序 没有固定的结构 用户可以根据需要输入嵌套信息 理想情况下 我需要一种方法来滚动浏览给定参数 一种类的类
  • Cordova Android 状态栏设置为透明

    我正在尝试使用下面的这个插件将状态栏设置为透明 但我无法实现它 我可以将其更改为不同的颜色 但不透明 https github com apache cordova plugin statusbar https github com apa
  • 下载旧版本的 Google App Engine SDK

    在哪里可以找到下载旧版 GAE SDK 例如 1 9 15 我需要找出覆盖范围 也许使用第 3 方 API 该 API 与最新版本不能很好地配合 这取决于相应的 SDK 是否仍受官方支持 这两种类型都可以在appengine sdks ht
  • 使用文本框输入在画布上移动对象

    我有一个画布 可以在上面添加图层 这些图层可以移动 选择 旋转 调整大小等 在画布下方 我显示图层的属性 x y 宽度 高度 我想做的是 当我更改包含 x 和 y 坐标的文本框中的值时 图层应该重新定位到我输入的坐标 我已经尝试了几件事 但
  • 在 Windows 中更改 Python 3 中的“区域设置首选编码”

    我正在使用 Python 3 最近从 Python 2 切换而来 我的代码通常在 Linux 上运行 但有时 不经常 在 Windows 上运行 根据 Python 3 文档open https docs python org 3 libr
  • 以编程方式单击时突出显示 TextView

    我动态生成 TextView 其工作方式类似于按钮 现在我想在他们受到压力时突出显示他们 比如更改文本颜色或背景颜色 我尝试过使用选择器 但它不起作用
  • 如何设置 PowerShell Cmdlet 的默认输出格式?

    我正在 C 中创建一个 PowerShell Cmdlet 以从 JSON 文件读取字段并输出一些对象 这些对象是简单的 POCO 类型 public class FieldDefinition public FieldDefinition
  • C#动态编译字符串和.cs文件

    我正在开发一个网站 用户可以在该网站上针对浏览器文本区域中的问题实现 C 代码解决方案并提交 然后 服务器将将该代码与我在服务器上提供的预定义接口一起编译 将其视为一种策略设计模式 我提供一个策略接口 由用户实现 所以我需要在运行时一起编译
  • 部分排序数组,最后 n 个元素已排序?

    有没有办法对数据数组执行部分排序 以便对最后 n 个元素进行排序 我的意思是使用标准库 而不是实现我自己的排序函数 这就是我现在正在做的事情 示例输出 使用较少的比较器 2 1 4 5 6 8 10 之后的元素 都大于之前的元素 但仅限于右
  • 共享一个控制器的角度多条路线

    我不确定我是否正确处理了这个问题 但我正在构建一个电子商务网站 该网站的一部分有 6 个不同的产品网格页面 每个页面都可以使用相同的视图 ul class products row li class product thumbnail co
  • ASP.NET / Web.config:customErrors 仅在 404 上重定向

    我有这样的场景 用户访问我的网站并点击不再存在的链接 他应该被重定向到自定义错误页面 这样可行 如果用户执行某些操作 引发错误 他应该看到堆栈跟踪和真正的错误页面 这是我当前的 Web config
  • 使用 PHP 文件功能在另一台服务器上创建文件

    我的一台服务器上有一个脚本 我希望该脚本使用 PHP 在我的另一台服务器上创建一个文件 而不是通过 FTP 有很多方法可以做到这一点 我自己会选择第一个 因为它最容易设置 如果你有PHP 另一台服务器上的Apache 只需使用以下命令调用另
  • 将 pfx 格式转换为 p12

    我需要导出一个 pfx将证书格式 来自 Windows MMC 转换为 p12在另一个应用程序中使用 我找不到办法做到这一点 任何人都可以建议一个方法吗 p12 and pfx都是 PKCS 12 文件 我错过了什么吗 您是否尝试过重命名导
  • 从父子表生成字符串树分支

    我有一个父子表 如下所示 child father H G F G G D E D A E B C C E 我希望 sql server 生成类似的东西 正如这个问题中所问的那样 将一系列父子关系转化为层次树 https stackover