Suppose that you have a table schema with a self-join (as shown below) and that the ManagerID of your CEO is NULL.
CREATE TABLE Employee
(
EmployeeID int NOT NULL IDENTITY(1,1) PRIMARY KEY
, JobTitle nvarchar(50) NOT NULL
, FirstName nvarchar(50) NOT NULL
, LastName nvarchar(50)
, ManagerID int
)
ALTER TABLE dbo.Employee ADD CONSTRAINT
FK_Employee_Employee FOREIGN KEY
(
ManagerID
) REFERENCES dbo.Employee
(
EmployeeID
) ON UPDATE NO ACTION
ON DELETE NO ACTION
GO
INSERT INTO Employee(JobTitle, FirstName, LastName, ManagerID)
Values ('Executive', 'Supreme', 'Leader', NULL)
INSERT INTO Employee(JobTitle, FirstName, LastName, ManagerID)
Values ('Manger', 'Boss', 'Man', 1)
INSERT INTO Employee(JobTitle, FirstName, LastName, ManagerID)
Values ('Minion', 'Bob', 'Minion', 2)
INSERT INTO Employee(JobTitle, FirstName, LastName, ManagerID)
Values ('Minion', 'Joe', 'Minion', 2)
GO
You can auto-generate an initial set of hierarchyid values using the following recursive CTE:
;WITH EmployeeHierarchy (
EmployeeHierarchyID
, EmployeeID
, JobTitle
, LastName
, FirstName
, ManagerID
)
AS (
SELECT HIERARCHYID::GetRoot() AS EmployeeHierarchyID
, EmployeeID
, JobTitle
, LastName
, FirstName
, ManagerID
FROM Employee
WHERE ManagerID IS NULL
UNION ALL
SELECT HIERARCHYID::Parse(Manager.EmployeeHierarchyID.ToString() + (
CONVERT(VARCHAR(20), ROW_NUMBER() OVER (
ORDER BY DirectReport.EmployeeID
))
) + '/') AS EmployeeHierarchy
, DirectReport.EmployeeID
, DirectReport.JobTitle
, DirectReport.LastName
, DirectReport.FirstName
, DirectReport.ManagerID
FROM EmployeeHierarchy AS Manager
INNER JOIN Employee AS DirectReport
ON Manager.EmployeeID = DirectReport.ManagerID
)
SELECT EmployeeHierarchyID
, EmployeeID
, JobTitle
, LastName
, FirstName
, ManagerID
INTO #EmployeeHierarchy
FROM EmployeeHierarchy
ORDER BY EmployeeHierarchyID
GO
It then becomes a fairly trivial matter to add a hierarchyid column to the table, add an index on it, and then populate it by joining to the temp table.
ALTER TABLE dbo.Employee ADD
EmployeeHierarchyID hierarchyid NULL
GO
UPDATE Employee
SET Employee.EmployeeHierarchyID = #EmployeeHierarchy.EmployeeHierarchyID
FROM Employee INNER JOIN
#EmployeeHierarchy ON Employee.EmployeeID = #EmployeeHierarchy.EmployeeID
GO
SELECT EmployeeHierarchyID.ToString() AS EmployeeHierarchyIDString, EmployeeID, JobTitle, FirstName, LastName, ManagerID, EmployeeHierarchyID
FROM Employee
GO
However, bear in mind that if you want the hierarchyid data to remain consistent after you add it, there are very specific ways in which it should be maintained.