Learn Hierarchies in SQL server using HierarchyID
What is Hierarchy ID ?
- Hierarchy ID is nothing other then column which represent relational value in numeric format on which DFS (Depth First Search) & BFS (Breadth First Search) can be used
- The concept is very simple, when we have to make relational structures which shows parent child level tree hierarchy, we can use hierarchyid datatype.
What Hierarchy ID do ?
- With hierarchy ID recursive queries can be converted into range query.
- DFS (Depth First Search) and BFS (Breadth First Search) can be implemented using additional index which improves performance.
- Uses .NET assembly library defined methods to provide easy maintenance.
- Hierarchy ID is scalar column and is sequence of no. of var binary values.
- Note: Range query are far better in performance compared to recursive queries.
Issue ?
- Integrity is not maintained automatically. Integrity is need to be maintained.
Lecture covers:
- Introduction
- Use of Function
- GetRoot()
- GetAncestor()
- IsDescendantOf()
- GetDescendant()
- GetReparentedValue()
- Converting existing relational hierarchy structure to hierarchyid implementation.
Functions
GetLevel() : Returns level of current node.
GetAncestor(nth) : Returns nth ancestor of current node.
IsDescendantOf(Pnode) : Returns all nodes where parent is Pnode
GetDescendant(child1,child2) : Returns hierarchyid between child1 and child2. In this child1 and child2 can be NULL depending upon requirement.
GetReparentedValue(oldRoot, newRoot): Return hierarchyid of node as per newRoot.
Script used:
DECLARE @hid HIERARCHYID
SET @hid = '/1/2/3/'
SELECT @hid.ToString(), @hid.GetAncestor(1).ToString() [Parent], @hid.GetAncestor(2).ToString() [Grand Parent], @hid.GetAncestor(3).ToString() [Root], @hid.GetAncestor(4).ToString() [No Parent]
WITH CTE(chain, NAME) AS (
SELECT CAST('/1/' AS HIERARCHYID), 'Ram'
UNION ALL
SELECT '/2/', 'Ron'
UNION ALL
SELECT '/1/1/', 'Sahil'
UNION ALL
SELECT '/1/2/', 'Mohit'
UNION ALL
SELECT '/2/1/', 'Maze'
UNION ALL
SELECT '/', 'Boss'
)
SELECT *
INTO #TEMP
FROM CTE
SELECT *, chain.ToString()
FROM #TEMP
SELECT NAME, chain, chain.ToString() [String Value], HIERARCHYID::GetRoot().ToString() [Root], chain.GetLevel() [Level]
FROM #TEMP
ORDER BY chain.GetLevel()
DECLARE @node HIERARCHYID
SET @node = '/1/';
SELECT NAME, chain, chain.ToString() [String Value], HIERARCHYID::GetRoot().ToString() [Root], chain.GetLevel() [Level]
FROM #TEMP
WHERE chain.IsDescendantOf(@node) = 1
AND chain != @node
AND chain.GetLevel() = @node.GetLevel() + 1
ORDER BY chain.GetLevel()
DECLARE @leftNode HIERARCHYID
DECLARE @rightNode HIERARCHYID
SET @leftNode = '/2/1/';
SET @rightNode = '/2/1/';
WITH CTE (node)
AS (
SELECT @leftNode.GetAncestor(1).GetDescendant(MAX(@rightnode), NULL) [GeneratedID]
)
SELECT node, 'More'
FROM CTE
DECLARE @oldNode HIERARCHYID, @newNode HIERARCHYID
SET @oldNode = '/1/';
SET @newNode = '/2/3/';
SELECT chain.ToString() [OldNode], NAME, chain.GetReparentedValue(@oldNode, @newNode).ToString() [NewNode]
FROM #TEMP
WHERE chain.IsDescendantOf(@oldNode) = 1
DROP TABLE #TEMP
Click here to download script.
|