Select departments with or without employees. Also select employees if assigned - sql

I want to select DNAME, DEPTNO from all departments with or without employees assigned. And if a department does have any employees I want to get their ENAME, EMPNO.
I tried this: select e.empno,e.name,d.deptno,d.dname from emp e full join dept d
on e.deptno=d.deptno
But it didn't work.
Table structure:
DEPT
DEPTNO DNAME
EMP
EMPNO ENAME DEPTNO

Use OUTER JOIN(LEFT/RIGHT)
SELECT D.DEPTNO,
D.DNAME,
E.EMPNO,
E.ENAME
FROM DEPT D
LEFT OUTER JOIN EMP E
ON D.DEPTNO = E.DEPTNO
When the Department does not have any employee then NULL will be displayed in E.EMPNO and E.ENAME column

SELECT
DEPT.DEPTNO,DEPT.DNAME,EMP.EMPNO,EMP.NAME
FROM
DEPT LEFT OUTER JOIN
EMP ON DEPT.DEPTNO = EMP.DEPTNO

Related

Select the manager name with the most employees

We have a table emp with columns empno, ename, job, mgr, hiredate, sal, comm, deptno
I have tried
SELECT m.ename, COUNT(e.empno) FROM emp e
INNER JOIN emp m ON e.empno = m.empno
GROUP BY m.ename HAVING COUNT(e.empno) = GREATEST(COUNT(e.empno));
My output is the names of the managers each with the value 1
How do we output the name of the manager with the most employees?
The following works:
SELECT COUNT(e.empno), m.ename FROM emp e
INNER JOIN emp m ON e.mgr = m.empno
GROUP BY m.ename HAVING GREATEST(COUNT(e.ename)) = COUNT(e.ename)
LIMIT 1;
First, fix the ON clause. Second, Use ORDER BY and LIMIT if you want one row:
SELECT m.ename, COUNT(e.empno)
FROM emp e INNER JOIN
emp m
ON m.empno = e.mgr
GROUP BY m.ename
ORDER BY COUNT(e.empno) DESC
LIMIT 1;
Your HAVING clause does not filter anything because any (non-NULL) value is equal to itself.

Perform SELECT statement inside of SELECT Statement?

I'm using Emp, Dept... databases. I would like to get the Name, Salary, Deptno and Average salary in the department of those employees who earn more than the average of their department. So here is what I'm trying to do:
SELECT e.Ename, e.Sal, e.Deptno
, (
SELECT AVG(Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
GROUP BY Deptno
) AS 'Average Salary'
FROM Emp e
WHERE e.Sal > (
SELECT AVG(b.Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
GROUP BY Deptno
);
And I can't use AVG(Sal), because it will give the average salary of the employee, and not the department where he works.
You would use a correlated subquery:
SELECT e.Ename, e.Sal, e.Deptno,
(SELECT AVG(e2.Sal)
FROM Emp e2
WHERE e2.Deptno = e.Deptno
) AS [Average Salary]
FROM Emp e
WHERE e.Sal > (SELECT AVG(e2.Sal)
FROM Emp e2
WHERE e2.Deptno = e.Deptno
);
But in actuality, you would just use a window function:
select e.*
from (select e.*, avg(sal) over (partition by deptno) as avg_sal
from emp e
) e
where sal > avg_sal;
Just get rid of the group by.
SELECT e.Ename, e.Sal, e.Deptno, (SELECT AVG(Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
) AS 'Average Salary'
FROM Emp e
WHERE e.Sal > (SELECT AVG(b.Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
);
If you join to the subquery, you will not need to repeat it.
SELECT e.Ename, e.Sal, e.Deptno, dAvgs.avgSal AS 'Average Salary'
FROM Emp AS e
INNER JOIN (
SELECT Deptno, AVG(b.Sal) AS avgSal
FROM Emp b
GROUP BY Deptno
) AS dAvgs
ON e.Deptno = dAvgs.Deptno AND e.Sal > dAvgs.avgSal
;

How to display deptno, deptname and no of employee?

I am practicing my SQL skills with "EMP" and "Dept" table given in Oracle 11g
I am trying to display department no , department name and no of employees of the department where employee no is greater than 4?
You can group by the department's details and apply a having condition:
SELECT d.deptno, d.deptname, COUNT(*)
FROM dept d
JOIN emp e ON d.deptno = e.deptno
GROUP BY d.deptno, d.deptname
HAVING COUNT(*) > 4

small tricky query on self join

I have a table EMP with columns as below:
create table emp(
empno number(4,0),
ename varchar2(10),
job varchar2(9),
mgr_id number(4,0),
sal number(7,2),
deptno number(2,0));
I want to list all employees' names along with their manager names, including those who do not have a manager. For those employees, their manager's name should be displayed as 'BOSS'.
The following query should work:
select e.ename, (case when m.ename is null then 'BOSS' else m.ename end) as mgrName
from emp e
left join emp m on m.empno = e.mgr_id
To my mind, the better solution is proposed by Charanjith.
In Oracle, we could even use NVL function instead of "case when" in order to replace null value by something. The result should be the same.
select e.ename empName, NVL(m.ename, 'BOSS') mgrName from emp e
left join emp m on m.empno = e.mgr_id
Moreover, we could see another solution : using inner join to filter on emp when a manager exists. Then union for all employees who don't have any manager.
select e.ename empName, m.ename mgrName from emp e inner join emp m on e.mgr_id = m.empno
union
select e.ename empName, 'BOSS' mgrName from emp e where not exists (select 1 from emp m where e.mgr_id = m.empno)
This work fine in oracle:
SELECT e.ename,
nvl(m.ename, 'BOSS')mgr
FROM emp a
LEFT JOIN emp b
ON m.empno = e.mgr_id;

How to show unused foreign key value when joining tables

I have 2 tables, emp, and dept(employee and department).
Say I want to show the sum of all salaries per department, I could use something like:
select sum(sal), deptno
from emp
group by deptno
Now that works, but say there is a department in the list that has no employees, and I want it to show up also, how would I do that? I've tried joins, the nvl function, but no luck this far. For example, this works, but it won't show the empty departments:
select sum(emp.sal), dept.deptno
from emp, dept
where emp.deptno=dept.deptno
group by dept.deptno
Thanks in advance for any help!
LEFT JOIN will do the trick:
select coalesce(sum(emp.sal),0), dept.deptno
from dept
left join emp on emp.deptno=dept.deptno
group by dept.deptno
You should always explicitly declare your joins, so that you can change them when you need to. Implicit joins are always INNER JOIN.
Additionally, I change the query to show 0 instead of NULL when department has no employees, by using COALESCE.
You need to use an outer join
SELECT
dept.deptno,
SUM(emp.sal)
FROM
dept
LEFT OUTER JOIN emp ON dept.deptno = emp.deptno
GROUP BY
dept.deptno
You want to use a LEFT JOIN so that you return all departments, regardless of whether or not they have employees.
SELECT dept.deptno, SUM(emp.sal)
FROM dept
LEFT JOIN emp
ON dept.deptno = emp.deptno
GROUP BY dept.deptno
Try this:
SELECT ISNULL(SUM(e.sal),0) AS SalSum,
d.DeptNo
FROM Dept AS d
LEFT JOIN emp AS e ON e.DeptNo = d.DeptNo
GROUP BY d.DeptNo
Use an outer join:
select
sum(emp.sal), dept.deptno
from dept LEFT OUTER JOIN emp
ON dept.deptno=emp.deptno
group by dept.deptno
Another alternative approach, justification being that it uses relational operators (union and difference) making it simple to read and understand, IMO:
select sum(sal), deptno
from emp
group by deptno
union
select 0, d.deptno
from dept d
minus
select 0, e.deptno
from emp e;
select sum(sal), deptno
from emp
group by deptno
union all
select 0, deptno
from dept
where deptno not in (select deptno from emp)
or
select sum(sal), deptno
from emp
group by deptno
union all
select 0, d.deptno
from dept d
where not exists
(
select *
from emp e
where e.deptno = d.deptno
)