SQL-在层次结构中选择子项以及父项

时间:2018-09-27 09:59:04

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

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

  • 1级(0级)
    • 第2分部(第1级)
      • 第3分部(第2级)
        • 第4分部(第3级)
      • 第5分部(第2级)
      • 第6分部(第2级)
    • 第7分部(第1级)
  • 第8分部(0级)
    • 第9分部(第1级)
    • 第10分部(第1级)
      • 11级(2级)

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

DivisionHierarchy

| 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      |

然后我有另一个带有选定分区的表:

SelectedDivisions

| DivisionID |
|          3 |
|         10 |

鉴于选择了Divisions,我需要过滤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      |

能否请您告诉我我该如何实现?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

通过将最后一部分重写为:

;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