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.
Related
Using set operator display the DEPTNO,SUM(SAL) for each dept, JOB,SUM(SAL) for each Job and Total Salary.
Using Set Operator display the JOB and Deptno in employees working in deptno 20,10,30 in that order.
for first question my query is this:
select e.deptno,to_char(null),e.sum(sal),
from emp e
UNION
select d.deptno,d.job,d.sum(sal)
from emp d
group by deptno,job;
I have no idea how to do the second one.
SET opetator can be union,intersection,minus...
The phrasing of the first question is not 100% clear to me, but the query should be:
select deptno, '', sum(sal) from emp group by deptno
union
select deptno, job, sum(sal) from emp group by deptno, job
For the second question you can use UNION again. For example:
select job, deptno
from (
select job, deptno, 2 as o from emp where deptno = 10
union
select job, deptno, 1 from emp where deptno = 20
union
select job, deptno, 3 from emp where deptno = 30
) x
order by o
I have a table Employee with those columns
empid, empname, job, hiredate, sal, comm, deptno
I want to verify if this is correct:
Number of employees in each department
How many people there are in each type of job in each department
Display the department and number of employees in department with fewer than 6 employees
Find the employee name and its salary who is earning maximum salary in dept 20
Here is what I have tried:
Query #1:
select DEPTNO, count(*) AS NO_OF_PERSONS
from EMP
group by DEPTNO;
Query #2:
select job, count(*) AS NO_OF_PERSONS
from EMP
group by job;
Query #3:
update EMPLOYEE
set sal = sal + 1000
where com > 2500;
And I am unable to do the 4th part.
I hope that below queries will help you.
no of employees in each dept?
SELECT DEPTNO,
count(*) AS NO_OF_PERSONS
FROM EMP
GROUP BY DEPTNO;
how many people are there in each type of job in each department?
SELECT job,
deptno,
count(*) AS NO_OF_PERSONS
FROM EMP
GROUP BY job,
deptno;
display the department and no of employees in department with fewer than 6 employee.
SELECT deptno,
count(*)
FROM emp
GROUP BY deptno
HAVING count(*) < 6;
find the employee name and its salary who is earning maximum salary in dept 20.
SELECT Max(salary_amount),
empid
FROM EMP
WHERE deptno = 20
GROUP BY empid;
You can start learning Basic SQL here
select e1.name, e1.sal
from EMP e1
where e1.DEPTNO = 20
and not exists(select *
from EMP e2
where e2.DEPTNO = 20
and e2.sal > e1.sal);
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.
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);
I am trying to do the following:
I have a table with ename, job, deptno, and sal. I am trying to initiate a query that returns the top earners of each department. I have done this with grouping and a subquery. However, I also want to display the average sal by deptno. So the following would be the result:
"ename" "dept" "sal" "average of dept"
sal 20 1000 500
kelly 30 2000 800
mika 40 3000 400
this might be impossible since the average does not associate with the other rows.
any suggestion would be appreciated. Thanks. I am using Oracle 10g to run my queries.
You could use analytic functions:
WITH RankedAndAveraged AS (
SELECT
ename,
dept,
sal,
RANK() OVER (PARTITION BY dept ORDER BY sal DESC) AS rnk,
AVG(sal) OVER (PARTITION BY dept) AS "average of dept"
FROM atable
)
SELECT
ename,
dept,
sal,
"average of dept"
FROM RankedAndAveraged
WHERE rnk = 1
This may return more than one employee per department if all of them have the same maximum value of sal. You can replace RANK() with ROW_NUMBER() if you only want one person per department (in which case you could also further extend ORDER BY by specifying additional sorting criteria to pick the top item, otherwise it will be picked randomly from among those with the maximum salary).
This should work. The only trick is that if you have several employees with the maximum salary in a department, it will show all of them.
SELECT t.ename, t.deptno, mx.sal as sal, mx.avg_sal as avg_sal
FROM tbl t,
(SELECT MAX(sal) AS sal, AVG(sal) AS avg_sal, deptno
FROM tbl
GROUP BY deptno) mx
WHERE t.deptno = mx.deptno AND t.sal = mx.sal
Not sure about Oracle, haven't used it in about 10 years, but something like this should be possible:
SELECT
ename, deptno, sal,
(SELECT AVG(T2.sal)
FROM tbl T2
WHERE T2.deptno = T.deptno
) AS average_of_dept
FROM tbl T
GROUP BY deptno
HAVING sal = MAX(sal)