【问题标题】:Sql HierarchyId How do I get the last descendants?Sql HierarchyId 如何获取最后的后代?
【发布时间】:2012-01-23 15:07:15
【问题描述】:

使用t-sql hierarchy Id 如何获取所有没有子代(即最后一个后代)的行?

假设我的表结构如下:

 Id, 
 Name,
 HierarchyId

并且有这些行:

1, Craig, /
2, Steve, /1/
3, John, /1/1/

4, Sam, /2/
5, Matt, /2/1/
6, Chris, /2/1/1/

约翰和克里斯会给我什么查询?

【问题讨论】:

    标签: sql sql-server hierarchyid


    【解决方案1】:

    您好,我使用这个,非常适合我。

    CREATE TABLE [dbo].[Test]([Id] [hierarchyid] NOT NULL,  [Name] [nvarchar](50) NULL)
    DECLARE @Parent AS HierarchyID = CAST('/2/1/' AS HierarchyID) -- Get Current Parent
    DECLARE @Last AS HierarchyID
    SELECT @Last = MAX(Id) FROM Test WHERE Id.GetAncestor(1) = @Parent -- Find Last Id for this Parent
    
    INSERT INTO Test(Id,Name) VALUES(@Parent.GetDescendant(@Last, NULL),'Sydney') -- Insert after Last Id
    

    【讨论】:

      【解决方案2】:

      也许有更好的方法,但这个接缝可以完成这项工作。

      declare @T table
      (
        ID int,
        Name varchar(10),
        HID HierarchyID
      )
      
      insert into @T values
      (1, 'Craig', '/'),
      (2, 'Steve', '/1/'),
      (3, 'John', '/1/1/'),
      (4, 'Sam', '/2/'),
      (5, 'Matt', '/2/1/'),
      (6, 'Chris', '/2/1/1/')
      
      select *
      from @T
      where HID.GetDescendant(null, null) not in (select HID 
                                                  from @T)
      

      结果:

      ID          Name       HID
      ----------- ---------- ---------------------
      3           John       0x5AC0
      6           Chris      0x6AD6
      

      2012-05-22 更新

      如果节点编号不是完整的序列,上述查询将失败。这是另一个应该解决这个问题的版本。

      declare @T table
      (
        ID int,
        Name varchar(10),
        HID HierarchyID
      )
      
      insert into @T values
      (1, 'Craig', '/'),
      (2, 'Steve', '/1/'),
      (3, 'John', '/1/1/'),
      (4, 'Sam', '/2/'),
      (5, 'Matt', '/2/1/'),
      (6, 'Chris', '/2/1/2/') -- HID for this row is changed compared to above query
      
      select *
      from @T
      where HID not in (select HID.GetAncestor(1)
                        from @T
                        where HID.GetAncestor(1) is not null)
      

      【讨论】:

        【解决方案3】:

        由于您只需要叶子并且不需要从特定的祖先获取它们,因此像这样的简单非递归查询应该可以完成工作:

        SELECT * FROM YOUR_TABLE PARENT
        WHERE
            NOT EXISTS (
                SELECT * FROM YOUR_TABLE CHILD
                WHERE CHILD.HierarchyId = PARENT.Id
            )
        

        简而言之:选择没有子行的每一行。

        这假设您的 HierarchyId 是指向 Id 的外键,而不是您的示例中显示的整个“路径”。如果不是,这可能是您应该在数据库模型中修复的第一件事。

        --- 编辑---

        好的,下面是实际有效的 MS SQL Server 特定查询:

        SELECT * FROM YOUR_TABLE PARENT
        WHERE
            NOT EXISTS (
                SELECT * FROM YOUR_TABLE CHILD
                WHERE
                    CHILD.Id <> PARENT.Id
                    AND CHILD.HierarchyId.IsDescendantOf(PARENT.HierarchyId) = 1
            )
        

        请注意,IsDescendantOf 将任何行视为其自身的后代,因此我们还需要条件中的 CHILD.Id &lt;&gt; PARENT.Id

        【讨论】:

        • 我相当肯定 OP 使用的是 SQL Server 2008 的 HierarchyID 数据类型,这解释了不寻常的表示形式(请参阅 msdn.microsoft.com/en-us/magazine/cc794278.aspx)。
        • @DanielPratt Ahh... 我现在看到问题被重新标记为 [sql-server]。
        • 感谢 Branko 的回复,但在我的示例中,Id 字段是一个整数,而 HierarchyId 是一个 sql HierarchyId,因此无法进行比较。你是说我需要把表的key改成hierarchyId?
        • @EricNeifert 我假设您使用“经典”设计来表示关系数据库中的分层数据,而不是 MS SQL Server 特定的机制。不幸的是,我对特定于 MS SQL Server 的机制不够熟悉,无法建议您是否应该实际进行切换,但似乎相同的基本思想也可以用于 MS SQL Server - 请参阅Mark Bannister's answer
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-24
        • 2011-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多