I am using the HierarchyId data type for the storage of locations. A user may be limited by location (LocationId
). If the user has more than 1 location limit the IsDescendantOf method on the HierarchyId data type has to be invoked again with an OR
.
Example(filter Employees by LocationId 5 and 6):
SELECT * FROM Employee
INNER JOIN Location ON Employee.LocationId = Location.LocationId
WHERE Location.Node.IsDescendantOf((SELECT TOP 1 Node
FROM Location
WHERE LocationId = 5)) = 1
OR
Location.Node.IsDescendantOf((SELECT TOP 1 Node
FROM Location
WHERE LocationId=6)) = 1`
This works fine for 2 LocationId
filters but what if this grows and a person has say 10 filters. Can IsDescendantOf work like the sql IN
clause?
Tables used:
CREATE TABLE Location (
LocationId int NOT NULL PRIMARY KEY IDENTITY(1,1),
Name nvarchar(100) NOT NULL,
[Node] hierarchyid NOT NULL,
[ParentNode] AS ([Node].[GetAncestor]((1))) PERSISTED,
[Level] AS ([Node].[GetLevel]()) PERSISTED,
);
CREATE TABLE [dbo].[Employee] (
[EmployeeId] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[LocationId] [int] NULL,
[Name] [nvarchar](50) NULL
) ;
Note: I addes the second solution (point 6).
1) You may use a table variable to store all searched locations (ex.
DECLARE @SearchedAncestorLocation TABLE(LocationId INT PRIMARY KEY)
).2) You have to find
HIERARCHYID's
nodes for every location ID from@SearchedAncestorLocation
.3) You have to do an
INNER JOIN
with employee's location using this filter:employee_location.Node.IsDescendantOf(searched_location.Node) = 1
.4) I think you should add an
UNIQUE(Node)
constraint toLocation
table to prevent duplicated locations (duplicated nodes).5) First solution: demo here.
Results:
Results if you uncomment the last line (
AND sl.Node <> el.Node
):6) Second solution.