Search code examples
sql-serversql-server-2008hierarchyid

How can I insert unique HierarchyId path without having to specify left and right sibling?


I am using HierarchyId in SQL to store the data. I am following the tutorial from here:

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

The examples that are mentioned in the sample are explicitly specifying position of the node:

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

Code is telling SQl that which are the sibling nodes of this particular Node. Which is OK. However, I all I want is that insert node at ANY position in the tree under a PARTICULAR parent. which means I want to be able to use something like:

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

WHich means

  • As far as the node is inserted under a correct parent, we do not care about the horizontal positioning of the node
  • When I tried GetDescendant(NULL,NULL) for multiple inserts for the same parent, it gives the same path /1/ to every child. Why is that?
  • Also, I came across following link: https://technet.microsoft.com/en-us/library/bb677212%28v=sql.105%29.aspx. which is showing an example of storing the last inserted child for a particular parent and then use it as a reference before inserting doing any further inserts into the DB. Is it the standart method for doing insert into a table with hierarchy to get the uniqueness in the path?

Solution

  • When I tried GetDescendant(NULL,NULL) for multiple inserts for the same parent, it gives the same path /1/ to every child. Why is that?

    A given instance of HierarchyId doesn't keep track of all of the descendants that it has. Indeed, I can do something like the following:

    declare @a hierarchyid = '/1/', @b hierarchyid = '/1/1/';
    
    select @b.IsDescendantOf(@a); --should be 1
    

    The thing to note in the example is that I created both @a and @b out of whole cloth (that is, I didn't create @b using the GetDescendant method). The point of the arguments to the GetDescendant method are so that it knows where in the list of siblings you'd like to place yours. If you don't care (and it seems that you don't based on your comments), the second argument will always be null (which is saying "make the new entry the last one in the list in a breadth-first traversal").

    All of this has been a long-winded way to say that if you pass NULL for both arguments, it's going to assume that there are currently no descendants under that particular instance of HierarchyId and so the one that you're asking for will be the first. Another way to think about it is that the GetDescendant method is deterministic (that is to say, given the same arguments, it will return the same answer every time).

    Is it the standart method for doing insert into a table with hierarchy to get the uniqueness in the path?

    It seems reasonable to me. I think about it this way: I'm going to call GetDescendant with the first argument being the last existing immediate descendant in a breadth-first traversal (possibly NULL if there are no existing descendants) and the second argument of NULL (since I'm just tacking it onto the end).