【问题标题】:Get all last members in a SQL Server hierarchy获取 SQL Server 层次结构中的所有最后成员
【发布时间】:2021-03-02 16:43:58
【问题描述】:

我正在尝试查找 SQL Server 层次结构中最后一个层次结构成员(“叶子”)的所有第一项。我能够找到类似的问题,但是 GetAncestors 的解决方案不适用于我们的 SQL Server 版本。

我能够使用这个解决方案:

SELECT 
    *, 
    CONVERT(nvarchar(20), MasterOrder) AS HierarchyString 
FROM 
    TestTable2 PARENT
WHERE
    NOT EXISTS (SELECT * 
                FROM TestTable2 CHILD
                WHERE CHILD.Id <> PARENT.Id 
                  AND CHILD.MasterOrder.IsDescendantOf(PARENT.MasterOrder) = 1)

这会返回正确的结果,但由于某种原因,只有 25 行中的 12 行。我认为NOT EXISTS 范围内包含太多行,但我没有使用CHILDPARENT 关键字的经验,有趣的是,未能找到它们的MS 文档。

编辑:我找不到它,因为我很累,不知何故没有注意到那些是别名,而不是关键字:-)

这是带有标记行 (&lt;&lt;&lt;) 的数据,查询应返回。

CREATE TABLE TestTable2
(
     RowNo       INT NOT NULL, 
     ID          INT NOT NULL, 
     MasterOrder HierarchyID NOT NULL,
     SeqNo       INT NOT NULL 
)

INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845192, '/', 1);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (3, 845196, '/1/', 3);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845194, '/1/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845193, '/1/', 1);      -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845238, '/10/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845239, '/10/', 1);     -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845242, '/11/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845241, '/11/', 1);     -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (3, 845245, '/12/', 3);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845244, '/12/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845243, '/12/', 1);     -- No! ...has children.
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845246, '/12/1/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845264, '/12/10/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845263, '/12/10/', 1);  -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845247, '/12/2/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845249, '/12/3/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845251, '/12/4/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845252, '/12/5/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845254, '/12/6/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845257, '/12/7/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845256, '/12/7/', 1);   -- <<< 
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845260, '/12/8/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845261, '/12/8/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845262, '/12/9/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (3, 845267, '/13/', 3);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845268, '/13/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845266, '/13/', 1);     -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (3, 845272, '/14/', 3);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845271, '/14/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845269, '/14/', 1);     -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (3, 845276, '/15/', 3);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845275, '/15/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845273, '/15/', 1);     -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845278, '/16/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845277, '/16/', 1);     -- No! ...has children.
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845279, '/16/1/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845296, '/16/10/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845297, '/16/10/', 1);  -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845299, '/16/11/', 1);  -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845301, '/16/12/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845302, '/16/12/', 1);  -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845304, '/16/13/', 1);  -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (3, 845309, '/16/14/', 3);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845308, '/16/14/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845306, '/16/14/', 1);  -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (3, 845313, '/16/15/', 3);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (2, 845312, '/16/15/', 2);
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845310, '/16/15/', 1);  -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845281, '/16/2/', 1);   -- <<<
INSERT INTO TestTable2 (RowNo, ID, MasterOrder, SeqNo) VALUES (1, 845282, '/16/3/', 1);   -- <<<

RowNo 列最初是我添加的ROW_NUMBER 列,它给出了相同层次结构项目的订单号(具有相同的层次结构字符串)。每个叶子总是有一个“1”,即使原始序列号以 3 开头(因为 1 和 2 由于它们的状态而被排除在外)。

所以任务是用RowNo = 1 获取所有“叶子”。

感谢任何帮助。

【问题讨论】:

    标签: sql sql-server parent-child hierarchyid


    【解决方案1】:

    好的,详细分析我发现问题显然在于,IsDescendantOf() 正在考虑 3 个具有相同层次结构值的不同行,即/13/ 是彼此的后代。我对后代的理解是它是一个“孩子”,尤其是因为文档似乎是这样说的:

    对以父节点为根的子树中的所有节点返回 true,对所有其他节点返回 false。

    但根据我的测试,它也返回 siblings

    一旦理解了问题,就很容易修复代码以获得正确的 25 行:

    SELECT 
        *, 
        CONVERT(nvarchar(20), MasterOrder) AS HierarchyString 
    FROM 
        TestTable2 as PARENT
    WHERE
        NOT EXISTS (SELECT * 
                    FROM TestTable2 as CHILD
                    WHERE RowNo = 1   -- <<< New condition <<<
                      AND CHILD.Id <> PARENT.Id 
                      AND CHILD.MasterOrder.IsDescendantOf(PARENT.MasterOrder) = 1)
                      ;
    

    RowNo = 1 添加到要排除的项目的选择中可确保仅在这些行上执行IsDescendantOf,因此没有兄弟姐妹可以扮演“假”子代。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 1970-01-01
      • 2015-07-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多