【问题标题】:SQL - Select child items in the hierarchy along with parent itemsSQL - 选择层次结构中的子项以及父项
【发布时间】:2018-09-27 09:59:04
【问题描述】:

在我的数据库中,我将不同级别的部门划分为层次结构:

  • 1 级(0 级)
    • 2 区(1 级)
      • 3 级(2 级)
        • 4 级(3 级)
      • 5 级(2 级)
      • 6 级(2 级)
    • 7 级(1 级)
  • 8 区(0 级)
    • 9 区(1 级)
    • 10 区(1​​ 级)
      • 11 级(2 级)

使用递归和 CTE,我生成了一个表,其中数据库中的所有分区按其层次结构路径排序(为方便起见为浮点值):

部门层级

| DivisionID | DivisionName | ParentID | Level | SortOrder |
|          1 | Division 1   | NULL     | 0     | 1         |
|          2 | Division 2   | 1        | 1     | 1.1       |
|          3 | Division 3   | 2        | 2     | 1.11      |
|          4 | Division 4   | 3        | 3     | 1.111     |
|          5 | Division 5   | 2        | 2     | 1.12      |
|          6 | Division 6   | 2        | 2     | 1.13      |
|          7 | Division 7   | 1        | 1     | 1.2       |
|          8 | Division 8   | NULL     | 0     | 2         |
|          9 | Division 9   | 8        | 1     | 2.1       |
|         10 | Division 10  | 8        | 1     | 2.2       |
|         11 | Division 11  | 10       | 2     | 2.21      |

然后我有另一个带有选定部门的表:

选定部门

| DivisionID |
|          3 |
|         10 |

给定选定的部门,我需要过滤 DivisionHierarchy 表以显示:

  • 选定的部门;
  • 选定部门的所有子部门(包括嵌套子部门);
  • 是所选分区的父分区,但仅限于在其结构路径中链接到它们的分区。

因此,对于 DivisionID IN (3, 10),输出应为:

  • 1 级(0 级)
    • 2 区(1 级)
      • 3 级(2 级)
        • 4 级(3 级)
  • 8 区(0 级)
    • 10 区(1​​ 级)
      • 11 级(2 级)。

输出:

| DivisionID | DivisionName | ParentID | Level | SortOrder |
|          1 | Division 1   | NULL     | 0     | 1         |
|          2 | Division 2   | 1        | 1     | 1.1       |
|          3 | Division 3   | 2        | 2     | 1.11      |
|          4 | Division 4   | 3        | 3     | 1.111     |
|          8 | Division 8   | NULL     | 0     | 2         |
|         10 | Division 10  | 8        | 1     | 2.2       |
|         11 | Division 11  | 10       | 2     | 2.21      |

您能告诉我如何实现这一目标吗?

【问题讨论】:

    标签: sql-server recursion common-table-expression hierarchy


    【解决方案1】:

    我尝试使用下面的脚本来完成它,但是它们是两个应该组合的查询结果(我不知道如何)。但也许它为您指明了正确的方向。

    DECLARE @DivisionHierarchy TABLE
    (
        DivisionID TINYINT NOT NULL,
        DivisionName VARCHAR(20) NOT NULL,
        ParentID TINYINT,
        [Level] TINYINT NOT NULL,
        SortOrder VARCHAR(20) NOT NULL
    )
    INSERT INTO @DivisionHierarchy VALUES (1, 'Division 1', NULL, 0, '1');
    INSERT INTO @DivisionHierarchy VALUES (2, 'Division 2', 1, 1, '1.1');
    INSERT INTO @DivisionHierarchy VALUES (3, 'Division 3', 2, 2, '1.11');
    INSERT INTO @DivisionHierarchy VALUES (4, 'Division 4', 3, 3, '1.111');
    INSERT INTO @DivisionHierarchy VALUES (5, 'Division 5', 2, 2, '1.12');
    INSERT INTO @DivisionHierarchy VALUES (6, 'Division 6', 2, 2, '1.13');
    INSERT INTO @DivisionHierarchy VALUES (7, 'Division 7', 1, 1, '1.2');
    INSERT INTO @DivisionHierarchy VALUES (8, 'Division 8', NULL, 0, '2');
    INSERT INTO @DivisionHierarchy VALUES (9, 'Division 9', 8, 1, '2.1');
    INSERT INTO @DivisionHierarchy VALUES (10, 'Division 10', 8, 1, '2.2');
    INSERT INTO @DivisionHierarchy VALUES (11, 'Division 11', 10, 2, '2.21');
    
    SELECT * FROM @DivisionHierarchy ORDER BY DivisionID;
    
    DECLARE @SelectedDivisions TABLE
    (
        DivisionID TINYINT
    );
    INSERT INTO @SelectedDivisions VALUES (3);
    INSERT INTO @SelectedDivisions VALUES (10);
    
    
    ;WITH CTE
    AS
    (
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN @SelectedDivisions s
                ON h.DivisionID = s.DivisionID
    
        UNION ALL
    
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN CTE c ON c.DivisionID = h.ParentID
    )
    SELECT * FROM CTE ORDER BY DivisionID
    
    ;WITH CTE
    AS
    (
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN @SelectedDivisions s
                ON h.DivisionID = s.DivisionID
    
        UNION ALL
    
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN CTE c ON c.ParentID = h.DivisionID
    )
    SELECT * FROM CTE ORDER BY DivisionID
    

    【讨论】:

    • 感谢您的回复。您可以将多个 CTE 合并为一个查询结果。通过重写我评论中看到的最后一部分,我已经达到了预期的结果。
    【解决方案2】:

    我通过将最后一部分改写为:

    ;WITH CTE_Parents
    AS
    (
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN @SelectedDivisions s
                ON h.DivisionID = s.DivisionID
    
        UNION ALL
    
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN CTE_Parents c ON c.DivisionID = h.ParentID
    ),
    CTE_Children
    AS
    (
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN @SelectedDivisions s
                ON h.DivisionID = s.DivisionID
    
        UNION ALL
    
        SELECT h.*
        FROM @DivisionHierarchy h
            INNER JOIN CTE_Children c ON c.ParentID = h.DivisionID
    )
    
    SELECT * FROM CTE_Parents
    UNION
    SELECT * FROM CTE_Children
    ORDER BY SortOrder
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多