I need to get the name of all of the employees that depends of a person directly or indirectly. Using the query in this example (from https://rextester.com/WGVRGJ67798),
create table employee(
id int not null,
employee varchar(10) not null,
boss int null
)
insert into employee values
(1,'Anna',null),
(2,'Bob',1),
(3,'Louis',1),
(4,'Sara',2),
(5,'Sophie',2),
(6,'John',4);
with boss as (
select id, employee, boss, cast(null as varchar(10)) as name
from employee
where boss is null
union all
select e.id, e.employee, b.id, b.employee
from employee e
join boss b on b.id = e.boss
)
select * from boss
I can get this result:
However, I need to see this:
It would be like showing all the possible relations between a person an all of those employees "below" him or her.
You can reverse the logic: instead of starting from the boss (the root) and going towards employees (the leafs), you could start from the leafs and walk toward the root. This lets you generate the intermediate relations as you go:
with cte as (
select e.id, e.employee, e.boss, b.employee name, b.boss new_boss
from employee e
left join employee b on b.id = e.boss
union all
select c.id, c.employee, c.new_boss, e.employee, e.boss
from cte c
join employee e on e.id = c.new_boss
)
select id, employee, boss, name
from cte
order by id, boss
Demo on DB Fiddle:
id | employee | boss | name
-: | :------- | ---: | :---
1 | Anna | null | null
2 | Bob | 1 | Anna
3 | Louis | 1 | Anna
4 | Sara | 1 | Anna
4 | Sara | 2 | Bob
5 | Sophie | 1 | Anna
5 | Sophie | 2 | Bob
6 | John | 1 | Anna
6 | John | 2 | Bob
6 | John | 4 | Sara
I like hierarchyid for this sort of thing.
use tempdb;
drop table if exists employee;
drop table if exists #e;
create table employee(
id int not null,
employee varchar(10) not null,
boss int null
)
insert into employee values
(1,'Anna',null),
(2,'Bob',1),
(3,'Louis',1),
(4,'Sara',2),
(5,'Sophie',2),
(6,'John',4);
with boss as (
select id, employee, boss,
cast(concat('/', id, '/') as hierarchyid) as h
from employee
where boss is null
union all
select e.id, e.employee, b.id,
cast(concat(b.h.ToString(), e.id, '/') as hierarchyid)
from employee e
join boss b on b.id = e.boss
)
select *
into #e
from boss
select e.id, e.employee, b.id, b.employee, b.h.ToString()
from #e as e
left join #e as b
on e.h.IsDescendantOf(b.h) = 1
and e.id <> b.id;
I took your code mostly as is and changed the following things:
Rather than keeping track of the boss in the recursive CTE, I'm building a hierarchyid path that leads all the way back to the root of the hierarchy.
Shoved the results of the cte into a temp table
Selected from the temp table, using a self-join where the join criteria are "where the inner table's notion of employee is anywhere in the management chain for the outer table".
Note, for the join, I'm excluding the case where the employee reports to themselves; you cannot be your own boss in this situation (even though the IsDescendantOf method would suggest otherwise!).
Something like this. There are two recursions. First, to get the h_level which with the first recursion represent boss-->employee relationships. Second, treats each row from the first as the leaf node in a new recursion to find direct and indirect hierarchical relationships.
Data
drop table if exists Employee;
go
create table employee(
id int not null,
employee varchar(10) not null,
boss int null)
insert into employee values
(1,'Anna',null),
(2,'Bob',1),
(3,'Louis',1),
(4,'Sara',2),
(5,'Sophie',2),
(6,'John',4);
Query
;with
boss(id, employee, boss, h_level) as (
select id, employee, boss, 0
from employee
where boss is null
union all
select e.id, e.employee, b.id, b.h_level+1
from employee e
join boss b on b.id = e.boss),
downlines(id, employee, boss, h_level, d_level) as (
select id, employee, boss, h_level, 0
from boss
union all
select b.id, b.employee, d.id, d.h_level, d.d_level+1
from boss b
join downlines d on d.id = b.boss)
select *
from downlines
order by h_level, d_level;
Output
id employee boss h_level d_level
1 Anna NULL0 0
2 Bob 1 0 1
3 Louis 1 0 1
4 Sara 2 0 2
5 Sophie 2 0 2
6 John 4 0 3
2 Bob 1 1 0
3 Louis 1 1 0
4 Sara 2 1 1
5 Sophie 2 1 1
6 John 4 1 2
4 Sara 2 2 0
5 Sophie 2 2 0
6 John 4 2 1
6 John 4 3 0
Sorry, couldn't think of a better title.
I have 3 tables in Oracle XE. An EMPLOYEE table a PROJECT table and a WORK_ON table. An EMPLOYEE can WORK_ON many PROJECTs. I am trying to get the employee name who is working on all the projects.
EMPLOYEE Table
Emp_ID EMP_Name
1 Esther
2 Peter
3 Joan
4 Roger
5 Liam
PROJECT Table
Project_ID
1
2
3
WROKS_ON Table
Emp_ID Project_ID
1 3
2 1
2 2
2 3
3 1
3 2
4 1
4 2
4 3
Given the fields my result should be Peter and Roger.
Started with the following, but got stuck:
SELECT EMP_NameLOYEE.E_NAME
FROM EMP_NameLOYEE INNER JOIN
(PROJECT INNER JOIN WROKS_ON ON PROJECT.Project_ID = WROKS_ON.Project_ID) ON
EMP_NameLOYEE.Emp_ID = WROKS_ON.Emp_ID
WHERE WROKS_ON.Project_ID In (SELECT DISTINCT Project_ID FROM PROJECT);
Obviously this retrieves all the names of the employees that are working on each project duplicated, but not exactly what I want.
You can leave the project table out of it.
SELECT e.emp_id, COUNT(project_id)
FROM employee e
INNER JOIN works_on wo ON wo.emp_id = e.emp_id
GROUP BY e.emp_id
HAVING COUNT( project_id ) = (SELECT COUNT(*) FROM project);
SQL Fiddle
You need to generate all combinations of employees and projects with a cross join and left join the works table and check for row counts for each e_name.
SELECT e.E_NAME
FROM EMPLOYEE e
CROSS JOIN PROJECT p
LEFT JOIN WORKS_ON w ON p.Project_ID = w.Project_ID and e.emp_id=w.emp_id
GROUP by e.E_NAME
HAVING COUNT(*)=COUNT(w.project_id)
I am having 3 tables
1 : Employee
2 : Department
3 : Experts
I want the experts which belong to CmpId = 1
Employee :
id CmpId
1 2
2 1
3 1
Department
id CmpId
1 1
2 2
3 2
Experts :
id EmployeeId DepartmentId
1 1 2
2 2 null
3 null 1
4 2 1
5 null null
Let me guess that NULL in the expert table means that someone is an expert for all departments. If so:
select e.employeeid
from experts e join
departments d
on e.departmentid = d.id or e.departmentid is null;
If I understand the question correctly, the desired results based on the sample data should be Expert ID's 2,3 and 4.
Expert ID 2 has an Employee ID of 2, which has a CmpID of 1.
Expert ID 3 has a Department ID of 1, which has a CmpID of 1.
Expert ID 4 has an Employee ID of 2, which has a CmpID of 1 and a Department ID of 1 which has a CmpID of 1.
If this is in fact the desired result set, I would write the following query.
SELECT ex.id, ex.EmployeeID, ex.DepartmentID
FROM #Experts ex
LEFT JOIN #Department dep
ON ex.DepartmentID = dep.id
LEFT JOIN #Employee emp
ON ex.EmployeeID = emp.id
WHERE dep.CmpID = 1 OR emp.CmpID = 1
That will yield the following results.
id EmployeeID DepartmentID
2 2 NULL
3 NULL 1
4 2 1
INNER JOIN the three tables
If they need to be CmpId = 1 in BOTH (this returns nothing in your sample data but assuming it is a larger data set)
SELECT e.id, e.EmployeeId, e.DepartmentId
FROM Experts e
FULL OUTER JOIN Department d ON e.DepartmentId = d.id
FULL OUTER JOIN Employee em ON e.EmployeeId = em.id
WHERE d.CmpId = 1 AND em.CmpId = 1
If they need to be CmpId = 1 in Either
SELECT e.id, e.EmployeeId, e.DepartmentId
FROM Experts e
FULL OUTER JOIN Department d ON e.DepartmentId = d.id
FULL OUTER JOIN Employee em ON e.EmployeeId = em.id
WHERE d.CmpId = 1 OR em.CmpId = 1
I have 3 tables and need to retrieve each EmployeeID, their Name, and their total WorkTime. My table structure is as follows:
DEPT TABLE
ID DEPTNAME DESIGNATION
1 MG MANAGER
2 AN ANALYTICS
3 DV DEVELOPER
4 PM PM
WORK TABLE
EMPID WORKTIME ID(FK TO TABLE DEPT) DATE
1 8 1 09/15/2014
2 7 2 09/15/2014
1 6 1 09/16/2014
2 8 2 09/16/2014
EMP TABLE
EMPID NAME
1 SK
2 TK
3 MK
4 CK
I want all the Employee names with ID and the total working time, as below:
EMPID NAME WORKTIME NOOFDATESWORKS
1 SK 14(8+6) 2
2 TK 15(7+8) 2
3 MK 0
4 CK 0
*please note: employees can work for multiple departments
SELECT E.EmpID,
E.Name,
W.TotalWorkTime
FROM Emp E
LEFT JOIN ( SELECT EMID, SUM(WorkTime) TotalWorkTime
FROM Work
GROUP BY EMID) W
ON E.EmpID =W.EMID
By the way, shouldn't the department Id be on the Emp table rather than the Work table?, as it is it doesn't make much sense to me
So there are three tables that would be applicable in this statement. The division table, which houses the division name and division id, the workon table which houses the projects and employee ids that correlate to the project, and the employee table that houses the employee id, department id, and name. I'm trying to find the department that has the most employees who work on projects.
This is my code:
select distinct
(dname) as "Division Name"
from
employee e, division d
where
d.did = e.did and
d.did in (
select did from employee where empid in (
select empid from workon having count(pid) >= all(pid)
)
)
I'm supposed to get the answer "human resources" but I cannot seem to get that answer no matter what code I use.
Workon table
PID EMPID HOURS
3 1 30
2 3 40
5 4 30
6 6 60
4 3 70
2 4 45
5 3 90
3 3 100
6 8 30
4 4 30
5 8 30
6 7 30
6 9 40
5 9 50
4 6 45
2 7 30
2 8 30
2 9 30
1 9 30
1 8 30
1 7 30
1 5 30
1 6 30
2 6 30
Employee Table
EMPID NAME SALARY DID
1 kevin 32000 2
2 joan 42000 1
3 brian 37000 3
4 larry 82000 5
5 harry 92000 4
6 peter 45000 2
7 peter 68000 3
8 smith 39000 4
9 chen 71000 1
10 kim 46000 5
11 smith 46000 1
Division
DID DNAME MANAGERID
1 engineering 2
2 marketing 1
3 human resource 3
4 Research and development 5
5 accounting 4
Check this reference out please.
SQLFIDDLE
select d.id, d.name, p.maxcounts
from dept d,
(select we.dep, max(we.counts) as maxcounts
from (select w.eid, count(w.pid) as counts,
e.dep as dep from employee e, workon w
where e.id = w.eid
group by e.dep) as we) as p
where d.id = p.dep
;
RESULTS:
ID NAME MAXCOUNTS
111 human resoruces 5
FOLLOWING is the edit based on your own data:
Reference : SQLFIDDLE_Based_ON_OP_Data
There are three ways you can achieve this. Either use the nested selects, save Max(count) into a variable or order data by desc and limit it to 1.
Method 1:
-- using nested select
--sub query 1 explaining to OP how final answer is derived
select e.dep, count(w.eid) as num_emp
from employee e, workon w
where e.id = w.eid
group by e.dep
order by e.dep
;
-- **results of sub query 1:**
DEP NUM_EMP
1 4
2 5
3 7
4 5
5 3
-- Final nested select query
select ee.dep, dd.name, count(ww.eid)
from employee ee, dept dd, workon ww
where ee.id = ww.eid
and ee.dep = dd.id
group by ee.dep, dd.name
having count(ww.eid) =
(select distinct max(t.num_emp)
from (select e.dep, count(w.eid) as num_emp
from employee e, workon w
where e.id = w.eid
group by e.dep
order by e.dep)as t)
;
-- results using nested selects
DEP NAME COUNT(WW.EID)
3 human resource 7
-- query using a variable
select max(x.num_emp) into #myvar from
(select e.dep, count(w.eid) as num_emp
from employee e, workon w
where e.id = w.eid
group by e.dep) as x
;
select x.dep, x.name, x.num_emp as num_emp from
(select e.dep, d.name, count(w.pid) as num_emp
from employee e, workon w, dept d
where e.id = w.eid
and e.dep = d.id
group by e.dep) as x
where x.num_emp = #myvar
;
-- results using variable
DEP NAME NUM_EMP
3 human resource 7
-- query using limit 1 with ordered desc table
select e.dep, d.name, count(w.eid) as num_emp
from employee e, workon w, dept d
where e.id = w.eid
and e.dep = d.id
group by e.dep
order by num_emp desc
limit 1
-- results using order by desc and limit 1:
DEP NAME NUM_EMP
3 human resource 7
Now when using Method 3, it may or may not matter to you that sometimes there will be two departments with same highest number of employees working in projects. So in that case you may use either nested or variable methods.
*PS I do not have the privilledge to be full time on StackOverFlow, hence sorry for getting back to you late :) *