Logical Processing of Recursive CTE - sql

I don't understand why the anchor is not called when the recursive member calls the cte.
Why does it go to the latest record (?) in the recursive part instead?
WITH Managers AS
(
--initialization
SELECT EmployeeID, LastName, ReportsTo
FROM Employees
WHERE ReportsTo IS NULL
UNION ALL
--recursive execution
SELECT e.employeeID,e.LastName, e.ReportsTo
FROM Employees e INNER JOIN Managers m
ON e.ReportsTo = m.employeeID
)
SELECT * FROM Managers

This is famous Microsoft sample database Northwind (immutable since 1997). The Emploeees table demonstrates hierarchical data and usage of recursive CTE (not available in 1997) to access it.
For better understanding / testing / training purpose add an extra column
WITH Managers AS
(
--initialization
SELECT EmployeeID, LastName, ReportsTo, /*extra column*/ 0 [level]
FROM Employees
WHERE ReportsTo IS NULL
UNION ALL
--recursive execution
SELECT e.employeeID,e.LastName, e.ReportsTo, [level]+1
FROM Employees e
INNER JOIN Managers m ON e.ReportsTo = m.employeeID
)
SELECT * FROM Managers
This is result set.
EmployeeID LastName ReportsTo level
----------- -------------------- ----------- -----------
2 Fuller NULL 0 --anchor call
--now 'Managers' CTE is the anchor (level 0)
1 Davolio 2 1
3 Leverling 2 1
4 Peacock 2 1
5 Buchanan 2 1
8 Callahan 2 1
--now 'Managers' CTE is resultset level 1
6 Suyama 5 2
7 King 5 2
9 Dodsworth 5 2
So the anchor executes always, recursive part executes iff the anchor returns row(s).

Related

List records from a chosen employee to the ultimate manager

Given the following Table (In Postgres):
EmployeeID
EmployeeName
ManagerID
1
David
NULL
2
Jessica
NULL
3
Gregg
1
4
Joe
3
5
Brandon
NULL
6
Leslie
4
7
Harry
6
8
Paul
NULL
9
Frank
5
Starting from Employee ID 7 (Harry) - how do I list only the records, bottom-up, in the hierarchy until I get to the ultimate manager (which should be David, in this case)? Should I use recursive CTE? If so, how does that query look?
Expected Output:
EmployeeID
EmployeeName
ManagerID
1
David
NULL
3
Gregg
1
4
Joe
3
6
Leslie
4
7
Harry
6
In the common table expression, you can recognize:
the base step, where you select the record relatively to employee no 7
the recursive step, where you match managers with currently retrieved employees.
The recursion stops when the INNER JOIN does not return any more extra record.
WITH RECURSIVE cte AS (
SELECT * FROM tab WHERE EmployeeID = 7
UNION ALL
SELECT mgr.*
FROM cte emp
INNER JOIN tab mgr
ON emp.ManagerID = mgr.EmployeeID
)
SELECT *
FROM cte
Check the demo here.

Displaying columns as rows SQL

I have the below tables:
Corporate table:
CorporateId DirectorId ManagerId SalesId
1 1 1 1
2 2 2 3
3 3 4 5
Employee table:
EmployeeId FirstName LastName
1 Tim Sarah
2 Tom Paulsen
3 Tam Margo
4 Eli Lot
5 Ziva Lit
I want to display, for one corporate,the names of the Director, Manager and Sales in rows. Example with corporate 3:
EmployeeId FirstName LastName
3 Tam Margo
4 Eli Lot
5 Ziva Lit
How can I do that? I know how to display rows as columns using pivot, but unsure if pivot can be used here also.
Any help please?
You may join the two tables as the following:
SELECT E.EmployeeId, E.FirstName, E.LastName
FROM Employee E JOIN Corporate C
ON E.EmployeeID IN (C.DirectorId ,C.ManagerId ,C.SalesId)
WHERE C.CorporateId=3
See a demo.
You can first un-pivot your rows into columns by using cross apply, after which you simply join the pivoted rows to your employee table:
select e.*
from corporate c
cross apply (
select EmployeeId from (
values (Directorid), (ManagerId), (SalesId)
)r(EmployeeId)
)r
join employee e on e.EmployeeId = r.EmployeeId
where c.CorporateId = 3;

How would one find the total cases by manager

I have two tables: one that has cases alongside the employees who resolve them and one that has information on the employees including their managers. I want to make a query that finds the amount of cases under each manager. Currently my query looks like this
select m.id, COUNT(distinct case when e.manager_id = m.id and a.resolver_id = e.id then a.ticket_id ELSE NULL END)
from tickets a
left join employee_info e on a.resolver_id= e.id
join employee_info m on e.manager_id = m.id
group by m.id
This query only gave me the count of the direct employees under a manager, not the count of all employees (including the ones under the people reporting directly to the manager). How would I tweak my query to include all employees under a person?
EDIT
So this is an obfuscated example of how my tables look
Ticket_id resolver_id
0001 11
0002 11
0003 13
0004 13
0005 12
0006 19
Id manager_id
11 01
12 01
13 11
19 12
and this is how I want my result to look
Id count
01 6
11 4
12 2
13 2
19 1
You essentially have a "tree" of employees, and want to recursively traverse it. This is what recursive CTEs are for.
We'll define a "subordinate" cte, that will tell us all the "subordinate relationships" between all employees, including "multi-level" subordination. If A is manager of B, and B is manager of C, then A has as subordinates B and C.
First, we start with all employees being their own subordinates. This is the non-recursive part.
SELECT id AS id1, id AS id2
FROM employee
Then, we "expand one level down" the subordinate relationships. if B is subordinate of A, all employees with B as manager are also subordinates of A. id1 stys as-is, id2 becomes the id of the "lower" employee. This is the recursive part.
SELECT s.id1, e.id
FROM subordinate s
JOIN employee e ON s.id2 = e.manager_id
Then we stick both in a recursive CTE. Postgres will iterate the 2nd part as many times as needed, until no new rows are added. This way we recusrively traverse the entire employee tree.
WITH RECURSIVE subordinate AS (
SELECT id AS id1, id AS id2
FROM employee
UNION
SELECT s.id1, e.id
FROM subordinate s
JOIN employee e ON s.id2 = e.manager_id
)
select * from subordinate order by id1, id2;
Let's check the result:
id1 | id2
-----+-----
1 | 1
1 | 11
1 | 12
1 | 13
1 | 19
11 | 11
11 | 13
12 | 12
12 | 19
13 | 13
19 | 19
Looking great! 1 has everyone as subordinates. 11 has 11 and 13, and lowst employees such as 13 and 19 only have themselves.
Once we have done this, the rest is easy.
We can do another CTE counting the resolved tickets per employee:
SELECT resolver_id as id, COUNT(*) as count
FROM tickets
GROUP BY resolver_id
and then we stick everything into the final query. For every employee, sum the resolved count of all its subordinates.
WITH RECURSIVE subordinate AS (
SELECT id AS id1, id AS id2
FROM employee
UNION
SELECT s.id1, e.id
FROM subordinate s
JOIN employee e ON s.id2 = e.manager_id
),
resolved as (
SELECT resolver_id as id, COUNT(*) as count
FROM tickets
GROUP BY resolver_id
)
SELECT s.id1, SUM(r.count)
FROM subordinate s
JOIN resolved r ON r.id = s.id2
GROUP BY s.id1;

How to Retrieve a Listing of Employee's Superiors in SQL

Essentially, I have a table that lists an employee's number and the employeeNumber of who they report to.
EmpNum | Name | ReportsTo
---------------------------------
1234 | John Smith | 4523
3245 | Annie Apples | 1234
1532 | Bob Rogers | 3245
6574 | Dong Wong | 1532
Etc. Etc. So Dong Wong's hierarchy would be: He reports to -> 1532 which reports to -> 3245 which reports to -> 1234.
(I'm new to SQL, so clean and understandable solutions would be appreciated)
By doing a join...
select e1.EmpNum, e1.name, e2.EmpNum as BossNum, e2.name as BossName from empTable e1 join empTable e2 on e1.ReportsTo=e2.EmpNum
The join can then be as long as you want, e3, e4... But doing it programatically is probably easier in the front end.
You didn't specify your DBMS so this is standard ANSI SQL
with recursive report_tree as (
select empnum, name, reportsto
from employees
where empnum = 6574
union all
select c.empnum, c.name, c.reportsto
from employees c
join report_tree p on p.reportsto = c.empnum
)
select *
from report_tree;
If you want a "graphical" display, you can do something like this (still standard ANSI SQL):
with recursive report_tree as (
select empnum, name, reportsto, name as report_path, 1 as level
from employee
where empnum = 6574
union all
select c.empnum, c.name, c.reportsto, p.report_path || ' -> ' || c.name, p.level + 1
from employee c
join report_tree p on p.reportsto = c.empnum
)
select *
from report_tree
order by level desc
fetch first 1 row only;
Try this, cte is best for recursion. SO already has many solutions for such problem
create table #emp(
EmpNum int,
Name varchar(50),
ReportsTo int
);
insert into #emp
values
(1234,'John',4523),
(3245,'Annie',1234),
(1532,'Bob',3245),
(6574,'Dong',1532)
with rec as (
select #emp.ReportsTo, #emp.EmpNum, #emp.Name, 1 as level from #emp where Name = 'Bob'
union all
select #emp.ReportsTo, #emp.EmpNum, #emp.Name, level + 1 as level from #emp
inner join rec
on #emp.EmpNum = rec.ReportsTo
)
select ReportsTo, EmpNum, Name, level from rec
where level = (select max(level) from rec)
OPTION (MAXRECURSION 0)

Get all employee who directly or indirectly reports to an employee, with hierarchy level no

I have a Employee table like
emp_id bigint,
reports_to bigint,
emp_name varchar(20),
Constraint [PK_Emp] Primary key (emp_id),
Constraint [FK_Emp] Foreign key (reports_to) references [MSS].[dbo].[Emp]([emp_id])
emp_id reports_to emp_name
------ ------ --------------
1 null Sumanta
2 1 Arpita
3 null Pradip
4 1 Sujon
5 2 Arpan
6 5 Jayanti
I want to get all the employees that directly or indirectly reports to Sumanta or emp_id(1), and with hierarchy level, like this:
emp_id hierarchy_level emp_name
------ --------------- ----------
2 1 Arpita
4 1 Sujon
5 2 Arpan
6 3 Jayanti
I am new to SQL and just couldn't find what to use or how to get those results. Is it worth a stored procedure with table valued variable, or just a Tsql select query will be enough. Any help is most welcome.
All I have done is-
Select Ep.emp_id,ep.emp_eame
From Emp as E
Inner Join Emp as Ep on Ep.reports_to=E.Emp_id
Where E.reports_to=1 or E.emp_id=1;
but this is accurate upto 2 level and I cant even generate the hierarchy_level no.
Any suggestion, idea............ will be most helpfull.........
You could use a recursive CTE:
; with CTE as
(
select emp_id
, reports_to
, emp_name
, 1 as level
from Emp
where emp_name = 'Sumanta'
union all
select child.emp_id
, child.reports_to
, child.emp_name
, level + 1
from Emp child
join CTE parent
on child.reports_to = parent.emp_id
)
select *
from CTE
Example at SQL Fiddle.
Using Common_Table_Expression we can write like this
WITH Employee_CTE(employeeid,hierarchy_level,name) AS
(
SELECT employeeid,1 as level,name from employee where employeeid=1
UNION ALL
SELECT e.employeeid,level +1, e.name
from employee e
INNER JOIN Employee_CTE c ON e.employeeid = c.managerid
)
SELECT * FROM Employee_CTE order by employeeid