Displaying the statistics from emp and dept table in a single query - sql

I have two table emp and dept
Emp table has following fields:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
Dept table has following fields:
DEPTNO DNAME LOC
Rules are:-
a. total employees in each department
b. highest salary of each department
c. least salary of each department.
d. No. of emps with highest salary in each department.
e. No. of emps with least salary in each department.
f. employee name/id with highest salary in each department.
g. employee name/id with least salary in each department.
h. Names of all employees belonging to eachdepartment.
o/p is as follows:
for data of emp and dept table refer this link
http://sqlfiddle.com/#!4/1bc2b8
Thanks in advance..

You can use analytical function and GROUP BY as follows:
SELECT D.deptno,
COUNT(1) TOTAL_EMPS,
MAX(sal) AS MAX_SAL,
MIN(sal) AS MIN_SAL,
SUM(CASE WHEN SAL = MINSAL THEN 1 END) EMP_MIN_SAL,
SUM(CASE WHEN SAL = MAXSAL THEN 1 END) EMP_MAX_SAL,
MAX(CASE WHEN RNMIN = 1 THEN E.empno END) EMP_WITH_MIN_sAL,
MAX(CASE WHEN RNMAX = 1 THEN E.empno END) EMP_WITH_MAX_sAL,
LISTAGG(E.ename, ',') WITHIN GROUP (ORDER BY E.EMPNO) ALL_EMPS
FROM dept D JOIN (SELECT T.*,
MIN(SAL) OVER (PARTITION BY deptno) MINSAL,
MAX(SAL) OVER (PARTITION BY deptno) MAXSAL,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY SAL) RNMIN,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY SAL DESC) RNMAX
FROM emp T) E
ON E.deptno = D.deptno
GROUP BY D.deptno;
SQLFiddle demo

Using aggregate functions and group by....without using any analytical functions
Select deptno,
COUNT(*) tot_emps,
MAX(sal) max_sal,
MIN(sal) min_sal,
COUNT(sal) KEEP (DENSE_RANK FIRST ORDER BY sal desc) emp_max_salary,
COUNT(sal) KEEP (DENSE_RANK FIRST ORDER BY sal asc) emp_min_salary,
MAX(empno || '-' || ename) KEEP (DENSE_RANK FIRST ORDER BY sal DESC) emp_with_max_salary,
MIN(empno || '-' || ename) KEEP (DENSE_RANK FIRST ORDER BY sal ASC)emp_with_min_salary,
LISTAGG(ename,',') WITHIN GROUP (ORDER BY ename) emp_list
FROM emp
GROUP BY deptno
ORDER BY deptno;
SQLFiddle_Demo

Related

How to get distinct column with max value and limit, hive

I have a table emp with around 10 rows
empno,ename,dept,sal,deptno
now I want result as ename from each dept who as max sal.
EX:
12,ravi,manager,20000,10
43,hari,engineer,10000,20
32,sam,clerk,5000,30
Get the max salary for each dept and then get the ename for each max salary.
select ename,dept,sal
from emp
where sal in (select max(sal) as sal from emp group by dept)
Using row_number() and partition
select * from
(
select ename,dept,sal, row_number() over (partition by dept order by sal desc) as row_no
from emp
) res
where res.row_no = 1

SQL select rows without duplicates

Practicing some SQL, we have to get the name of the employees whose salary is the greatest of his department. But if in any department there were more than one employer with the greatest salary, we would not have to consider that department.
We got the first part but not the second one (because there are two employees with the same greatest salary (3,000) in the same department (20)).
This is what we did:
SQL> SELECT ename, sal, deptno FROM emp a
WHERE sal >= ALL (SELECT sal FROM emp WHERE deptno=a.deptno)
ORDER BY sal;
And this is what we got:
ENAME SAL DEPTNO
---------- ------- ------
BLAKE 2,850 30
FORD 3,000 20
SCOTT 3,000 20
KING 5,000 10
4 filas seleccionadas.
Any help will be useful, thank you!
SELECT ename, sal, deptno
FROM emp a
WHERE not exists (
SELECT *
FROM emp
WHERE deptno=a.deptno
and sal >= a.sal
and ename != a.ename)
ORDER BY sal;
with cte as
( SELECT ename, sal, deptno
, row_number() over (partition by deptno order by sal desc) as rn
FROM emp
)
select ename, sal, deptno from cte where rn = 1
except
select ename, sal, deptno from cte where rn = 2
order by sal
if this does not work in oracle - it used to be also tagged mssql
You can have what you need with some analytic functions:
select ename,
deptno,
sal
from (
select ename,
deptno,
sal,
row_number() over(partition by deptno order by sal desc) AS num,
count(1) over(partition by deptno, sal) AS count
from emp
)
where num = 1
and count = 1
The inner query orders by salary and counts the number of employees with the same salary in the same department; the outer one simply filters for employees with the maximum salary, where only one employee has that salary in the department.
With a different approach, simply modifying your query, you can try:
SELECT ename, sal, deptno FROM emp a
WHERE sal >= ALL (SELECT sal FROM emp WHERE deptno=a.deptno)
and (select count(1) from emp b where a.deptno = b.deptno and a.sal = b.sal) = 1
The first way gives better performance, with a single table scan, while the second one needs a nested query, thus being less efficient
try to use GROUP BY column_name`, it will show the record without duplicate.

How to get two highest salary in emp table?

BREAK ON DEPTNO SKIP 1
compute sum of sal on deptno
SELECT deptno, empno, ename,sal FROM
(SELECT deptno, empno, ename, sal FROM emp )
WHERE EXISTS (SELECT deptno FROM dept) order by 1,2 , sal desc ;
How can I get two highest sal from emp, and what is wrong with my code?
If you want all rows with the two highest distinct salaries in each department, then use dense_rank() as follows:
select deptno, empno, ename, sal
from (select e.*,
dense_rank() over (partition by deptno, order by sal desc) as seqnum
from emp e
) e
where seqnum <= 2
order by deptno, sal desc;
It looks like the question will be deleted, but it might as well have a correct answer.
It is not entirely clear what you want. In the title you say "two highest salary", but in the comment you mention something about a sum.
The following will show the two highest salaries. If there are multiple "highest" salaries, all will be shown
select deptno, empno, ename, sal
from (
SELECT deptno, empno, ename, sal,
dense_rank() over (order by sal desc) as rnk
FROM emp
)
where rnk <= 2
order by sal desc;
To get this per department, you can use this:
select deptno, dept_salary
from (
select deptno, dept_salary,
dense_rank() over (order by dept_salary desc) as rnk
from (
SELECT deptno, sum(sal) as dept_salary
FROM emp
group by deptno
) t1
) t2
where rnk <= 2
order by dept_salary desc
Simple query actually:
SELECT deptno, empno, ename,sal FROM emp eb
WHERE (deptno, empno) IN
(SELECT depno, empno FROM
(SELECT deptno, empno FROM emp ei
WHERE ei.deptno = eb.deptno
ORDER BY ei.sal DESC
) WHERE rownum <= 2
);
The last WHERE rownum <=2 differ from SQL to SQL, in Mysql you would need LIMIT 2, in MSSQL Server, you would need to do SELECT TOP 2, in Oracle WHERE rownum <= 2. Depends on the engine you use.

oracle SQL : getting DEPT by min and max sums

I have 2 working subqueries that checks what are the min and max SUMS in all departments (DEPTNO). Table EMP and DEPT has DEPTNO cells
(SELECT min(sum(e.SAL)) FROM EMP e GROUP by e.DEPTNO);
(SELECT max(sum(e.SAL)) FROM EMP e GROUP by e.DEPTNO);
How to check what is the DEPTNO for min- and max- subquery?
My code is with ERROR:
SELECT d.DEPTNO
FROM DEPT d
WHERE sum(e.SAL) = (SELECT max(sum(e.SAL)) FROM EMP e GROUP by d.DEPTNO);
If you want the department withe the max sum, you can use rownum or row_number():
select ed.*
from (select e.deptno, sum(e.sal) as sums,
row_number() over (order by sum(e.sal) desc) as seqnum
from emp e
group by e.deptno
) ed
where seqnum = 1;
In Oracle 12g+, this can also be written as:
select e.deptno, sum(e.sal) as sums,
row_number() over (order by sum(e.sal) desc) as seqnum
from emp e
group by e.deptno
order by sum(e.sal) desc
fetch first 1 row only;
This is one way to do it using cte
with salsums as (select deptno, sum(sal) salsum from emp group by deptno)
, maxandmin as (select max(salsum) maxsal, min(salsum) minsal from salsums)
select deptno
from salsums cross join maxandmin
where salsum = maxsal or salsum = minsal
Ok, this is harder than it looks at first. This is how I ended up getting it to work but I like #vkp's answer more.
with sums as
(
SELECT DEPTNO, SUM(SAL) AS SSAL
FROM EMP
GROUP BY DEPTNO
), mm as
(
SELECT DEPTNO, SSAL, MIN(SSAL) OVER () as MIN_SSAL, MAX(SSAL) OVER () as MAX_SSAL
FROM SUMS
)
SELECT 'MIN', DEPTNO, SSAL FROM mm WHERE SSAL=MIN_SSAL
UNION ALL
SELECT 'MAX', DEPTNO, SSAL FROM mm WHERE SSAL=MAX_SSAL
http://sqlfiddle.com/#!6/410c8/8

sql subqueries and group by

I'm having an assignment for my sql class which i can't seem to figure out. This is the description of the select wanted:
Show all employees of which the salary is higher than the average of the colleagues in their department, only for the departments with at least 4 employees.
I've been able to find parts of the query like
select ename
from emp
where sal > any (select avg(sal)
from emp
group by
deptno);
to get the names of the employees which earn more than the avg.
or
select count(deptno)
from emp
group by
deptno having count(deptno) > 4;
to getthe number of employees in each department.
But somehow it doesn't work linking them together. Maybe someone can help me shine a light on this on.
Just put your second query in with an AND clause:
select ename
from emp
where sal > any (select avg(sal)
from emp
group by
deptno)
and deptno in (select deptno
from emp
group by
deptno having count(deptno) > 4);
You can use Having Clause in Conjunction with Group By
select ename
from emp
where sal > any (select avg(sal)
from emp
group by
deptno)
having count(*)>4;
select ename
from (
select deptno, count(deptno)
from emp
group by deptno
having count(deptno) > 4) valid_depts join emp ON emp.deptno=valid_depts.deptno
where sal > any (select avg(sal)
from emp
group deptno);