Level1, level2, level3.. nth level display of managers of an employee sql - sql

Can someone please let me know how this can be accomplished?
I have a table with following fields and data- employeeid, email are unique
what my output should look like for Donnie-
I have to append the hierarchy to each employee row. Suppose employee- don's manager bob has katie as direct manager instead of john then it should get displayed as level1->john, level2->katie,level3->bob, ename->don, direct manager-bob. This could go up to 5 levels. If one of the managers left the job then the employee should get assigned to the prior level manager.
Thanks for your help in advance

First of all, you need to fix your table design so it uses managerid, not managername; at the moment your model doesn't allow for two managers with the same first name.
Secondly, please tag your question with the DBMS you are using.
If you are sure there are only going to be a maximum of 5 levels then just left outer join the table to itself 5 times - each time using the managerid of the current instance of the join joined to the employeeid of the next instance of the join:
SELECT ...
FROM table a
left outer join table b on a.managerid = b.employeeid
left outer join table c on b.managerid = c.employeeid
...
If the hierarchy might change then you ought to be looking at hierarchical queries - but the syntax for these are often DBMS-specific, hence the request for you to tag your question with the DBMS you are using (though you should do this anyway as it's good practice)

with s (eid, ename, mname, lvl) as
(select eid, ename, mname, 1 as lvl
from tbl
union all
select eid, ename, mname, a.lvl+1
from s a,
tbl b
where a.mname=b.ename)
select eid,
max(ename),
max(mname),
max(case when lvl=1 then mname end) lv11name,
max(case when lvl=2 then mname end) lv12name,
max(case when lvl=3 then mname end) lv13name
from s ;
This query is working for me. I still have to accommodate the scenario where if manager left the job, I need to update the employee hierarchy to the prior level supervisor. Please let me know how that can be handled in the above sql

Related

SQL Server : replace several instances of userID with username

I may be overthinking this but I have not managed to figure it out or find a solution, so I'm hoping for a pointer in the right direction. I tried using the Select ColumnA AS Column B etc but it's not doing what I want.
I have 2 tables, scenario examples below
Table 1 (Vehicle)
VehicleID (001)
VehicleMake (Ford)
VehicleModel (Falcon)
VehicleExCleanEmpID (005)
VehicleIntCleanEmpID (003)
Table 2 (Employee)
EmpID (005)
EmpName (Dave)
The scenario being that a vehicle is cleaned internally or externally by any one of a pool of employees shown by the relevant ID in the Vehicles table.
I want to show in a query VehicleID, InsideCleanName, ExternalCleanName rather than showing the employee's ID.
So end up with results similar to this
VehicleID InsideCleanName ExternalCleanName
------------------------------------------------
001 Bob Dave
002 Sue Dave
003 John Sid
Thanks for any tips and or help
THat seems like a pretty simple query with two inner joins to the Employee table - something like this:
SELECT
v.VehicleId,
InsideCleanName = e1.EmpName,
ExternalCleanName = e2.EmpName
FROM
dbo.Vehicle v
INNER JOIN
dbo.Employee e1 ON v.VehicleIntCleanEmpId = e1.EmpID
INNER JOIN
dbo.Employee e2 ON v.VehicleExCleanEmpId = e2.EmpID
Joining to the Employee e1 table is giving you the employee who was responsible for the inside cleaning, while joining a second time, to Employee e2 gives you the one responsible for the external cleaning.
Join the two table with EmpId and select the columns you want similar to the code below:
select column1, column2 from table1 inner join table2 on table1.EmpId = table2.EmpId

Hierarchical query with join. Performance issue

I am trying to form a query that fetch the details of subordinates under multiple level of supervisors. The hierarchy is as follows:
General manager- regional manager- district manager - supervisor - employee
My requirement is that, any manager in this hierarchy should be able to see the details of the employee at the bottom of the hierarchy.
So far I have tried the following options:
1: 102 seconds to execute
WITH w AS
( select personId from assignments start with supervisorId = :inputId
Connect by prior personId = supervisorId)
Select columns FROM a,b
where a.column = b.column
And a.personId = w.personId;
2: 92 seconds
Select columns FROM a,b
where a.column = b.column
And a.personId IN ( select personId from assignments start with supervisorId = :inputId
Connect by prior personId = supervisorId);
3:0.75 seconds[no data fetched]
WITH w AS ( select columns FROM a,b
where a.column = b.column)
Select w.columns from w, assignments
Where t.personId = assignments.personId
Start with supervisorId = :inputId
Connect by prior personId = supervisorId.
In option 3, since join condition is executed first before connect by, that could be why it does not return any rows. Please note that when fetching data for a single employee, it takes less than a second to execute, ie by removing the hierarchical query part and the assignments table and giving personId of a single person.
So I am looking for an efficient solution to meet this requirement. Any method, even not including hierarchical queries are welcome.
Thanks,
Anoop

Select highest association when given record's level is random

There are three tables involved. DBMS is Oracle 10g.
Employees = individual employee records
Emp_id (PK)
Emp_name
various detail fields
Department = contain hierarchical org structure
Dept_code (PK)
Department Name
Parent_id (refers to dept_code in same table for parent dept)
depth_level (1=highest level, 2=sub-depts of 1, etc ... max = 6)
various details fields
Association = mapping employees to departments
Assoc_id (pk)
emp_id (fk)
dept_code (fk)
other fields that relate different association types
Where the association maps employees to departments at various depths, I want to run a query that counts all employees grouped at depth = 2. If an employee works in a dept at level 6, I would need to resolve level 5, then level 4, then level 3 to get to level 2, but if they work in a dept at level 3, I only need to resolve to level 2.
Trying to figure out the most efficient way. So far, I'm looking at running 5 separate queries, one for each depth with varying numbers of subqueries to resolve the depth levels and then combining with union. My second thought was to create a static reference table to map each department code to a level 2 label, but maintaining that table would be problematic.
Anybody got any better ideas?
Recursive CTE saved the day. I apologize if my question wasn't clear, here is my solution although I may have changed some of the field names from the original post. I plan to replace the static value for U.ID in the first part of the union query with a parameter that will any department code and retrieve its respective subordinate departments.
In this case dept code '5000002' is the IT department, the results display all employees in various levels of the IT department hierarchy.
select r.full_name, r.id, u.dept_name, u.dept_id, u.dept_level
from clarity.srm_resources r,
clarity.PRJ_OBS_ASSOCIATIONS a,
(with DIRECT_DEPT (Parent_ID, Dept_ID, Dept_Name, Dept_Level)
as
(
SELECT U.PARENT_ID, U.ID AS DEPT_ID, U.NAME AS DEPT_NAME, 0 AS Dept_Level
FROM clarity.prj_obs_units u
where u.type_id = '5000001'
AND U.ID = '5000002'
UNION ALL
SELECT U.PARENT_ID, U.ID AS DEPT_ID, U.NAME AS DEPT_NAME, Dept_Level +1
FROM clarity.prj_obs_units u
INNER JOIN DIRECT_DEPT D
ON U.PARENT_ID = D.DEPT_ID
where u.type_id = '5000001'
)
SELECT Parent_ID, Dept_ID, Dept_Name, Dept_Level
FROM DIRECT_DEPT) u
where a.record_id = r.id
and a.unit_id = u.dept_id
and a.table_name ='SRM_RESOURCES'
and r.is_active = '1'
;

Replacing a table value with the previous expression in oracle

Ok so I am having the following scenario
I have a table called employees and have to replaced the last names for some of the people there under the following conditions:
1-The last name must be replaced only to those employees who work on Oxford.
2-Their new last name is going to be the last name of the person that has their employee number -1 ( for instance employee#173 should have now employee#172 last name instead)
This is how I started the query:
select last_name,num_emp
from employees
where num_emp in(
select e.num_emp
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
And I did a second query to make sure which values were going to replace which
Select last_name,num_emp
from employees
where num_emp in(
select (e.num_emp-1)
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
Now I thought I could do this and make the code work... but it didn't:
update employees
set last_name=(select last_name
from employees
where num_emp in(
select (e.num_emp-1)
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
Got error saying unexpected end of SQL command...
So I thought on making a change because I believed having too many values on the set was not the point and here is how I did it for last time:
update employees
set last_name=(select last_name
from employees)
where num_emp =(
select (e.num_emp-1)
from employees
join departments using(num_dept)
join office using(id_office)
where city='Oxford')
Got an error that says is missing right parenthesis, which I know it does not express whaat the issue is. I know I am missing something and part of the sintaxis is wrong as well as I may need to créate another table and add those values so that they get saved there and I can compare them with the original ones, but at this point I am totally blocked and can't discover what is the mistake I am doing. Please help me I'd really apprecciate it!
You are getting confused with what to update and what to update with in your statements.
Here is what to update. I use IN clauses to make it plain. An EXISTS clause would also be appropriate.
update employees
set last_name = ...
where num_dept in
(
select num_dept
from departments
where id_office in
(
select id_office
from office
where city = 'Oxford'
)
);
And here is what to update with:
set last_name =
(
select last_name
from employees prev_employee
where prev_employee.num_emp = employee.num_emp - 1
)
You should use the analytical lag function, then you also fill in gaps if for example employee 172 doesn't exist and you have to put the name of employee 171 in 173.
Your select should be something like this
with new_emp as
(select last_name,lag(last_name, 1, 0) over (order by num_emp) as new_last_name, num_emp
from employees)
select *
from new_emp
where num_emp in(
select e.num_emp
from employees e
join departments using(num_dept)
join office using(id_office)
where city='Oxford');
This select will give you the original last name, new last name, employee number.
Then afterwards your update should be this:
update employees x
set last_name = (with new_emp as
(select last_name,lag(last_name, 1, 0) over (order by num_emp) as new_last_name, num_emp
from employees)
select new_last_name
from new_emp ne
where ne.num_emp = x.num_emp)
where x.num_emp in(
select e.num_emp
from employees e
join departments using(num_dept)
join office using(id_office)
where city='Oxford');

Deriving a column's data from a matching column in SQL

So I have a table that has, employee number, employee name, supervisor number.
I want to run a query that will retrieve employee name, employee number, supervisor name and supervisor number. Only one employee doesn't have a supervisor meaning it will have to display nulls. How would I do this? I'm using Oracle SQL Plus. My attempts haven't worked at all! Any help would be much appreciated.
SELECT ename Employee, empno Emp#, super Manager#
FROM emp;
That gets me three of the columns but to be honest I don't even know where to start to get the supervisors names.
It's for university, but I'm studying for a test it's not for an assignment so no cheating happening here :).
The following should work, and give you nulls if the employee has no supervisor:
SELECT empGrunt.ename Employee
, empGrunt.empno EmpNum
, empSuper.ename SupervisorName
, empSuper.empno SupervisorName
FROM emp empGrunt LEFT OUTER JOIN emp empSuper
ON empGrunt.super = empSuper.empno
Assuming that SupervisorNumber is a foreign key relationship back to the Employee table (where it's the EmployeeNumber of the supervisor's record), then you need to use an outer join.
What you need in this case is a left join:
select
e.EmployeeName,
e.EmployeeNumber,
s.EmployeeName as SupervisorName
from Employee e
left join Employee s on s.EmployeeNumber = e.SupervisorNumber