【问题标题】:SQL Parent child tree data return only completed tree nodes from listSQL 父子树数据仅从列表中返回已完成的树节点
【发布时间】:2018-04-18 15:21:06
【问题描述】:

我在 SQL 数据库中有父子树关系。有许多表包含我所有的数据/关系,为此我需要的重要数据在下表中,我正在使用递归 CTE 查询来获取它。我的应用程序和数据库设计非常适合我正在做的事情。我需要进行一些管理/维护以确认数据是否正确,并且我正在尝试做的事情概述如下:

我的数据集包含的是: - FilterID - 这是父记录 ID - 深度 - 在我的 CTE 中,这给了我该树关系的记录数。 - sortCol - 在我的 CTE 中,我正在构建它(这只是所有 FilterID 的组合二进制字符串) - TreeListOfFilterIDs - 这是此级别记录的树中所有 FilterID 的列表。 - 我想要的结果 - 这是我添加的一列,用于标识我想从数据集中返回的字段列表

在本例中,FilterID 35 是起始记录。父子关系可以有 1 个父节点和 2 个(或更多)不同的子路径,因此 1 个父节点可以有 2 个或更多不同的子节点。注意:这种关系是有意的,因为 1 个父母可以有 2 个不同的孩子,我在我的代码/流程中使用它。

我需要从下面的数据集中得到的是只返回每个节点中父/子关系的最终路径的记录。我在下面的数据中添加了一个我没有从我的查询中获得的名为“我想要的结果”的列,我只想获取其中包含“X”的记录。

我正在填充表格,并且我的代码/流程正在使用我设计所有内容的方式。我现在尝试用这个逻辑完成的是找到唯一的最终路径,这样我就可以轻松识别每条最终路径并确保它们是正确的。这将用于维护目的,以监控数据和路径。

FilterID    depth   sortCol                                                 TreeListOfFilterIDs     RESULTS I WANT
35          0       0x00000023                                              35
36          1       0x0000002300000024                                      35,36
37          2       0x000000230000002400000025                              35,36,37
39          3       0x00000023000000240000002500000027                      35,36,37,39             X
38          2       0x000000230000002400000026                              35,36,38
40          3       0x00000023000000240000002600000028                      35,36,38,40
44          4       0x000000230000002400000026000000280000002C              35,36,38,40,44          X
41          3       0x00000023000000240000002600000029                      35,36,38,41
45          4       0x000000230000002400000026000000290000002D              35,36,38,41,45          X
42          3       0x0000002300000024000000260000002A                      35,36,38,42
46          4       0x0000002300000024000000260000002A0000002E              35,36,38,42,46          X
43          3       0x0000002300000024000000260000002B                      35,36,38,43
47          4       0x0000002300000024000000260000002B0000002F              35,36,38,43,47
48          5       0x0000002300000024000000260000002B0000002F00000030      35,36,38,43,47,48       X
49          5       0x0000002300000024000000260000002B0000002F00000031      35,36,38,43,47,49       X

请注意,以上数据来自我的 CTE 结果,但按 sortcol 值排序(因此这不是数据插入 CTE 的顺序)。

生成上述结果的SQL:

-- this combines the required answers for the next questions to display (will join to what is filled out in the form
IF OBJECT_ID('tempdb..#RequiredAnswersToFindNextFiltersToDisplay') IS NOT NULL
    DROP TABLE #RequiredAnswersToFindNextFiltersToDisplay

CREATE TABLE #RequiredAnswersToFindNextFiltersToDisplay (       
    FilterID INT,           
    FormAssociationID INT,  
    RequiredAnswerFilterID INT
)


-- this gets the RequiredAnswersIntoA String for joining on
INSERT INTO #RequiredAnswersToFindNextFiltersToDisplay (
    FilterID, FormAssociationID, RequiredAnswerFilterID
)


VALUES
( 35, 1, 0 ), 
( 36, 2, 35 ), 
( 37, 3, 36 ), 
( 38, 4, 36 ), 
( 39, 5, 37 ), 
( 40, 6, 38 ), 
( 41, 7, 38 ), 
( 42, 8, 38 ), 
( 43, 9, 38 ), 
( 44, 10, 40 ), 
( 45, 11, 41 ), 
( 46, 12, 42 ), 
( 47, 13, 43 ), 
( 48, 14, 47 ), 
( 49, 15, 47 )



;WITH ItemDataCTE(FilterID, FormAssociationID, RequiredAnswerFilterID, depth, sortcol, TreeListOfFilterIDs)
AS (
  -- anchor member
  SELECT FilterID, FormAssociationID, RequiredAnswerFilterID, 0, CAST(FilterID AS VARBINARY(900)) AS SortCol,
  CAST(FilterID AS VARCHAR(MAX)) AS TreeListOfFilterIDs
  FROM #RequiredAnswersToFindNextFiltersToDisplay
  WHERE RequiredAnswerFilterID = 0

  UNION ALL

  SELECT ID.FilterID, ID.FormAssociationID, ID.RequiredAnswerFilterID, M.depth + 1, CAST(M.SortCol + CAST(ID.FilterID AS BINARY(4)) AS VARBINARY(900)) SortCol,
  CAST(M.TreeListOfFilterIDs + ',' + CAST(ID.FilterID AS VARCHAR(50)) AS VARCHAR(MAX)) AS TreeListOfFilterIDs     
  FROM #RequiredAnswersToFindNextFiltersToDisplay ID      
  INNER JOIN ItemDataCTE AS M ON ID.RequiredAnswerFilterID = M.FilterID   
)

SELECT *
FROM ItemDataCTE
ORDER BY ItemDataCTE.sortcol

【问题讨论】:

  • edit您的问题将示例数据包含为 DDL+DML。最好能显示源表(我想你现在显示的是递归 cte 的结果)
  • 很高兴您展示了 DDL,但我们仍然需要示例数据。请完成插入语句,以便我们将问题中的代码复制到测试环境中。
  • @Zohar Peled 对此表示抱歉,已更新为包含数据插入

标签: sql-server recursion parent-child


【解决方案1】:

最简单的方法是使用not exists向递归cte添加一个自连接:

SELECT *
FROM ItemDataCTE as c0
WHERE NOT EXISTS
(
    SELECT 1
    FROM ItemDataCTE AS c1
    WHERE c1.TreeListOfFilterIDs LIKE c0.TreeListOfFilterIDs +',%'
)
ORDER BY sortcol

结果:

FilterID    FormAssociationID   RequiredAnswerFilterID  depth   sortcol                         TreeListOfFilterIDs
39          5                   37                      3       00035000360003700039            35,36,37,39
44          10                  40                      4       0003500036000380004000044       35,36,38,40,44
45          11                  41                      4       0003500036000380004100045       35,36,38,41,45
46          12                  42                      4       0003500036000380004200046       35,36,38,42,46
48          14                  47                      5       000350003600038000430004700048  35,36,38,43,47,48
49          15                  47                      5       000350003600038000430004700049  35,36,38,43,47,49

【讨论】:

  • 我知道回复/回答已经晚了,但我使用了您上面发布的大部分内容,并对其进行了一些调整。
  • 很高兴我能帮上忙 :-)
猜你喜欢
  • 2023-04-07
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-20
相关资源
最近更新 更多