Get the output based on column in the same table - sql

I have a table which looks like this:
Employee table:
Employee_id E_Name Manager_Id
-------------------------------
1 p -
2 q 1
3 r 1
4 s 2
Here column Manager_Id denotes the manager's employee Id. Meaning for p there is no manager. for q and r employee with id 1 is manager (p). and for s employee with emp id 2 is manager.
I want to build a query which will return below result:
Employee_id E_Name Manager_Name
-------------------------------
1 p -
2 q p
3 r p
4 s q
table here has manager name instead of id.
How to achieve above? Thanks in advance

It can easily be done with a LEFT OUTER JOIN:
Try this:
SELECT a.EMPLOYEE_ID, a.E_NAME, b.E_NAME
FROM EMPLOYEE a left outer join EMPLOYEE b
on A.MANAGER_ID = B.EMPLOYEE_ID

you did not mentioned the database provider, but for MySQL, it is:
SELECT e.employee_id, e.e_name,COALESCE(m.e_name,'-') AS Manager_Name
FROM employee e
LEFT JOIN employee m ON m.employee_id = e.manager_id

Please try:
select
Employee_id,
E_Name,
(select E_Name from YourTable b where b.Employee_id=a.Manager_Id) as Manager_Name
from YourTable a

Related

How to Query Hierarchical Data in SQL and determine height of each user

I have an Azure SQL table containing all the employees in a company. I use the below query to determine the height of each employee:
WITH emp AS (
SELECT *, 0 AS d
FROM tableA
WHERE Email = '<email>'
UNION ALL
SELECT e.*, emp.d + 1
FROM tableA e INNER JOIN emp
ON e.ManagerId = emp.Id
)
SELECT max(d)
FROM emp e
Is there a more efficient way to determine the height all the employees in the company without recursively running the above query for each employee?
UPDATE:
Here is my table structure:
Id ManagerId Email
1 -1 CEO
2 1 ABC
3 1 DEF
4 2 PQR
5 2 STU
6 3 EPS
7 3 DMN
Is there a more efficient way to determine the height all the employees in the company without recursively running the above query for each employee?
You can do it all with a single recursive query if you start with the top-level employees and recurse down their reporting hierarcies, something like:
WITH emp AS (
SELECT *, 0 AS d
FROM tableA
WHERE ManagerId is null
UNION ALL
SELECT e.*, emp.d + 1
FROM tableA e INNER JOIN emp
ON e.ManagerId = emp.Id
)
SELECT e.Id, e.ManagerId, max(e.d) over () - e.d depth
FROM emp e

Oracle error: ORA-00979: not a GROUP BY expression

Following is the result of my first query (in Oracle). Totals is the total number of employees in each department (so Employee 1-5 are on department#1, employees 6-8 on department#2 etc.)
select a.name, (select count(*) from employee b where a.dname = b.dname group by b.dname) as totals
from employee a;
NAME TOTALS
------------------------------ ----------------
Employee 1 5
Employee 2 5
Employee 3 5
Employee 4 5
Employee 5 5
Employee 6 3
Employee 7 3
Employee 8 3
Employee 9 4
Employee 10 4
Employee 11 4
Employee 12 4
And here is my second query on which employer has less taskhours than 5 (note "taskhours" is a different field than "totals" in the database)
select a.name
from job o, employee a, works w , task t
where w.name=a.name and w.menuid=o.menuid and w.worktype='office' and t.fname = o.fname
group by a.name
having sum(t.taskhours) <5
;
NAME
------------------------------
Employee 3
I want now combine the above, i.e query for the employees who have fewer task-hours than the total employees in the department. I am trying this query
select a.name
from job o, employee a, works w , task t
where w.name=a.name and w.menuid=o.menuid and w.worktype='office' and t.fname = o.fname
group by a.name
having sum(t.taskhours) <(select count(*) from employee b where a.sname = b.sname group by b.sname)
but I get the error:
ERROR at line 5:
ORA-00979: not a GROUP BY expression
Can someone help me find the right query?
Sample data for 1st query:
NAME DNAME
------------------------------ ------------------------------
Employee 1 Dep1
Employee 2 Dep1
Employee 3 Dep1
Employee 4 Dep1
Employee 5 Dep1
Employee 6 Dep2
Employee 7 Dep2
Employee 8 Dep2
Employee 9 Dep3
Employee 10 Dep3
Employee 11 Dep3
Employee 12 Dep3
We can phrase this by putting each of your two queries into subqueries, and then joining them together:
SELECT
e.name,
e.dname,
t1.emp_cnt,
t2.hours_cnt
FROM employee e
LEFT JOIN
(
SELECT dname, COUNT(*) AS emp_cnt
FROM employee
GROUP BY dname
) t1
ON e.dname = t1.dname
LEFT JOIN
(
SELECT a.name, SUM(t.taskhours) AS hours_cnt
FROM works w
INNER JOIN employee a
ON w.name = a.name
INNER JOIN job o
ON w.menuid = o.menuid
INNER JOIN task t
ON t.fname = o.fname
WHERE w.worktype = 'office'
GROUP BY a.name
) t2
ON e.name = t2.name
WHERE
t1.emp_cnt < t2.hours_cnt;
You can simplify the first query as follows
use that as a cte block
with tot_count
as (select dept_id,count(emp_id) as dept_cnt
from employee
group by dept_id)
,less_than_five
as (select a.name
,sum(t.taskhours) as sum_taskhours
,max(a.dept_id) as dept_id_of_emp
from job o,
employee a,
works w ,
task t
where w.name=a.name
and w.menuid=o.menuid
and w.worktype='office'
and t.fname = o.fname
group by a.name
)
select *
from less_than_five a
join tot_count b
on a.dept_id_of_emp=b.dept_id
where less_than_five.sum_taskhours<=b.dept_cnt

SQL: Retrieve all records where has all joined

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)

how to get manager's name from employ name

How do I find manager name here. Each manager is also an employee.
EmpID Name ManagerId
1 A 3
2 B 1
3 C 2
4 D 5
5 E 1
Expected result is like this
EmpID Name ManagerName
1 A C
2 B A
3 C B
4 D E
5 E A
You have to use Left Join for the desired output..otherwise you will miss some employee who doesn't have managers ..
SELECT e.empid, e.name Employee, ISNULL(e1.name,'') Manager
FROM employee e
LEFT JOIN employee e1 on e.managerid = e1.empid
You can self join the table, and use the joined instance to get the manager's name:
SELECT e.empid, e.name, m.name
FROM employee e
JOIN employee m on e.managerid = m.empid
CREATE TABLE #MYTEMP
(
EmpID INT
,Name VARCHAR(10)
,ManagerId INT
)
INSERT INTO #MYTEMP VALUES
(1,'A',3),( 2,'B',1),(3,'C',2),(4,'D',5),( 5,'E',1)
SELECT EMP.EmpID AS EMPNO,
EMP.Name AS EMPLOYEE,
MGR.Name AS MANAGER
FROM #MYTEMP EMP
JOIN #MYTEMP MGR
ON EMP.ManagerId = MGR.EmpID

how to display records which is present in employee but not present in department table

i want to get records which is present in employees table but not in department
i.e (Employees - department)
output should be like this
Employee(ID,Name), Department(Id,Name)
i tried this
select * from Employee as e
left join Department as d on e.DeptId = d.ID
sample data
ID Name DeptId Salary ID Name
1 krishna 1 5000 1 developer
2 rakesh 2 8000 2 trainer
3 sanjay 3 9000 3 programmer
4 swapna 4 6000 4 seo
6 shiva 6 4000 NULL NULL
i want to show records of shiva because he is in table employee but not in department table in sql server
Either use an OUTER JOIN as you've already done and filter by d.ID is null(as Dave has already shown). Or use NOT EXISTS which is my favorite:
select e.*
from Employee e
where not exists
(
select 1 from Department d
where e.DeptId = d.ID
)
Pros and cons of all approaches:
Should I use NOT IN, OUTER APPLY, LEFT OUTER JOIN, EXCEPT, or NOT EXISTS?
I had a little difficulty understanding the question but with your existing query a WHERE clause could be used to only show records that don't have an appartment.
select * from Employee as e
left join Department as d on e.DeptId = d.ID
WHERE d.ID is null
Alternatively
select
*
from Employee as e
WHERE e.ID not in (SELECT d.ID FROM Department d)