What is the best way to do a recursive SQL query on a self join field (as well as doing it through nhibernate?)

StackOverflow https://stackoverflow.com/questions/23420153

Question

I have a database table called Employee and it the following columns:

  • Id
  • Name
  • ManagerId

The column called ManagerId is a self join field in the same table (as a manager is just another employee.

I now want to run a query that :

Take in a parameter of Id (taking a single manager) and want to get all of the people that roll up into that person. So if I do

 Select * from ManagerId = 1

I will only get the direct reports of that manager and i want to get EVERYONE that rolls up to that manager recursively.

  • The direct reports
  • The direct reports of the direct reports
  • The direct reports of the direct reports of the direct reports
  • etc . . .

Also, I am using fluent nhibernate in my solution so also would like to get some suggestions there as well. If i do this in a loop in code it seems like it will running many queries if a manager has a number of layers of people under them.

Was it helpful?

Solution

Using a recursive CTE, you can build the hierarchy. Filtering the top level query by your search criteria, you can get the results you're looking for.

DECLARE @id INT;
SET @id = 3;

WITH    Emp
          AS (SELECT    te.id
                      , te.Name
                      , te.ManagerId
                      , CAST(NULL AS VARCHAR(10)) AS ManagerName
              FROM      dbo.tblEmployee AS te
              -- Get entire heirarchy with the NULL ManagerId
              --WHERE     ManagerId IS NULL
              WHERE     te.id = @id
              UNION ALL
              SELECT    te2.id
                      , te2.Name
                      , e.id
                      , e.Name
              FROM      dbo.tblEmployee AS te2
              JOIN      Emp e
                        ON e.id = te2.ManagerId
             )
    SELECT  *
    FROM    Emp;

UPDATE: For your comment about not including the record for the id passed, you can do two things:

The easiest way would be to add a where clause to the last select:

SELECT  *
FROM    Emp
WHERE emp.ID <> @id;

Alternatively, if you didn't need the ManagerName field to be populated for the top level of the hierarchy, you can what the first where clause in the CTE:

SELECT    te.id
, te.Name
, te.ManagerId
, CAST(NULL AS VARCHAR(10)) AS ManagerName
FROM      dbo.tblEmployee AS te
-- Get entire heirarchy with the NULL ManagerId
--WHERE     ManagerId IS NULL
--WHERE     te.id = @id
WHERE ManagerId = @id
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top