1

我在 SQL 中使用 HierarchyId 来存储数据。我正在关注这里的教程:

http://www.codeproject.com/Tips/740553/Hierarchy-ID-in-SQL-Server

示例中提到的示例明确指定了节点的位置:

DECLARE @parent HierarchyId = (SELECT Node FROM H WHERE Name = 'Thuru')
DECLARE @jhony HierarchyId = (SELECT Node FROM H WHERE name = 'Johnny')
INSERT INTO H (Node,ID,Name) VALUES (@parent.GetDescendant(@jhony,NULL), 3, 'Robert') 

代码告诉 SQl 哪些是这个特定节点的兄弟节点。这没关系。但是,我想要的只是在特定父级下的树中的任何位置插入节点。这意味着我希望能够使用类似的东西:

DECLARE @parent HierarchyId = HierarchyId::GetRoot()
INSERT INTO H (Node,ID,Name) VALUES (@parent.GetDescendant(NULL,NULL),2,'Johnny') 

意思是

  • 只要节点插入到正确的父节点下,我们不关心节点的水平定位
  • 当我尝试 GetDescendant(NULL,NULL) 为同一父项进行多次插入时,它为每个子项提供了相同的路径 /1/。这是为什么?
  • 另外,我遇​​到了以下链接:https ://technet.microsoft.com/en-us/library/bb677212%28v=sql.105%29.aspx 。它显示了为特定父级存储最后插入的子级的示例,然后在将其插入到数据库中进行任何进一步插入之前将其用作参考。它是插入具有层次结构的表以获得路径唯一性的标准方法吗?
4

2 回答 2

2

当我尝试 GetDescendant(NULL,NULL) 为同一父项进行多次插入时,它为每个子项提供了相同的路径 /1/。这是为什么?

HierarchyId 的给定实例不会跟踪它拥有的所有后代。确实,我可以执行以下操作:

declare @a hierarchyid = '/1/', @b hierarchyid = '/1/1/';

select @b.IsDescendantOf(@a); --should be 1

示例中要注意的是,我用整块布创建了@a 和@b(也就是说,我没有使用该GetDescendant方法创建@b)。该GetDescendant方法的参数的重点是,它知道您想在兄弟姐妹列表中的哪个位置放置您的兄弟姐妹。如果您不在乎(而且您似乎不基于您的评论),第二个参数将始终为空(这表示“在广度优先遍历中将新条目设为列表中的最后一个” )。

所有这一切都是一种冗长的说法,如果你为两个参数都传递 NULL,它会假设当前在那个特定的 HierarchyId 实例下没有后代,所以你要求的那个将是第一的。另一种思考方式是该GetDescendant方法是确定性的(也就是说,给定相同的参数,每次都会返回相同的答案)。

它是插入具有层次结构的表以获得路径唯一性的标准方法吗?

在我看来这很合理。我是这样想的:我将调用GetDescendant第一个参数是广度优先遍历中最后一个现有的直接后代(如果没有现有的后代,可能是 NULL)和 NULL 的第二个参数(因为我只是把它贴到最后)。

于 2015-02-10T06:05:33.323 回答
0

由于所有常见的原因,我不太喜欢游标。但是,使用基于集合的 INSERT INTO..SELECT 对于 IDENTITY 列和 SEQUENCES 效果很好,但不适用于 HIERARCHYID。因此,我使用这种方法多次插入到具有共同父级的层次结构中。它可以在您有多个级别的地方级联。

-- This would add all employees who are managers from an 
-- Employee table (with employee_id and isManager columns)
-- as descendants of an existing root node in an OrgChart table

BEGIN TRAN

DECLARE @root hierarchyid
DECLARE @lastNode hierarchyid
DECLARE @employee_id INT 

SELECT @root = hierarchyid::GetRoot() FROM [dbo].[OrgChart]
SELECT @lastNode = NULL -- GetDescendant(NULL, NULL) for the first descendant

-- Have to use a cursor because using set based INSERT INTO..SELECT
-- with hierarchy gives each row the same hierarchyid

DECLARE c CURSOR FOR 
SELECT employee_id 
FROM [dbo].[Employees]
WHERE
    [isManager] = 1 

OPEN c  
FETCH NEXT FROM c INTO @employee_id 

WHILE @@FETCH_STATUS = 0  
BEGIN  
    INSERT INTO
        [dbo].[OrgChart](
            orgID,
            [effective_start_date], 
            effective_end_date, 
            employee_id
            )
    SELECT
        @root.GetDescendant(@lastNode, NULL),
        GETDATE(),
        NULL,
        @employee_id

    -- Get the hierarchyid you have just added 
    -- so you can add the next one after it
    SELECT @lastNode = orgID FROM [dbo].[OrgChart]

    FETCH NEXT FROM c INTO @employee_id
END 

CLOSE c  
DEALLOCATE c 

COMMIT
于 2019-07-31T14:44:37.977 回答