I have the following ORACLE query where I attempt to find the department with the highest average salary. I would like to use in-line view (i.e. retain the b dataset) for this implementation, but struggle to get the right part at the WHERE and GROUP BY components. I know the below GROUP BY and WHERE (which is non-existant) is wrong. But how do i correct them?
select a.deptno from emp a,
(select max(avg_sal) max_avg_sal from (select
avg(sal) avg_sal from emp group by deptno) ) b
group by a.deptno, b.max_avg_sal
having avg(a.sal) = b.max_avg_sal
Expected Result
deptno
10
Emp Structure
deptno staff sal
10 A 1000
10 B 1500
11 C 1100
12 D 1000
12 E 900
12 F 1000
Is this what you want?
select e.*
from (select e.*, avg(e.salary) over (partition by e.deptno) as avg_salary
from emp e
) e
order by avg_salary desc
fetch first 1 row only;
fetch first is available in Oracle 12c+. You can do similar things with an additional subquery in earlier versions.
You can use subquery
select deptno from tablename
group by deptno
having avg(sal)= (select max(asal) from (select avg(sal) as asal from tablename group by deptdno)A)
The straight-forward way is:
select deptno
from emp
group by deptno
order by avg(salary) desc
fetch first row with ties;
FETCH FIRST is available as of Oracle 12c.
In Oracle 11g we could use this instead:
select deptno
from
(
select deptno, avg(salary) as avg_salary, max(avg(salary)) over () as max_avg_salary
from emp
group by deptno
)
where avg_salary = max_avg_salary;
But you want an inline view, another word for a derived table (a subquery in the from clause). That looks way more clumsy. One example without FETCH FIRST and without window functions:
with d as
(
select deptno, avg(salary) as avg_salary
from emp
group by deptno
)
, dmax as
(
select max(avg_salary) as max_avg_salary
from d
)
select d.*
from d
join dmax on dmax.max_avg_salary = d.avg_salary;
I find this very obfuscated and don't recommend it at all. You can do the same without WITH clauses of course. Then it is even less readable.
I don't know why you'd want to write it this way, but if you really want only inline views and no windowing clauses, you can write it this way:
select b.deptno
from (SELECT deptno, avg(sal) avgsal from emp group by deptno ) b
cross join (SELECT max(avgsal) maxavgsal FROM (SELECT avg(sal) avgsal FROM emp group by deptno )) c
where b.avgsal = c.maxavgsal;
This the same thing, if you don't like CROSS JOIN for some reason:
select b.deptno
from (SELECT deptno, avg(sal) avgsal from emp group by deptno ) b
inner join ( SELECT max(avgsal) maxavgsal FROM
( SELECT avg(sal) avgsal FROM emp group by deptno ) ) c
on b.avgsal = c.maxavgsal;
Related
Have to find the most experienced employee.
select empno, ename,
from emp
where max(months_between(SYSDATE,hiredate))
My software is giving errors on sysdate, so could anyone please verify if this is correct.
Use NOT EXISTS:
select e.empno, e.ename
from emp e
where not exists (select 1 from emp where hiredate < e.hiredate)
or:
select empno, ename
from emp
where hiredate = (select min(hiredate) from emp)
or modify the WHERE clause of your query like this:
select empno, ename
from emp
where months_between(SYSDATE, hiredate) = (
select max(months_between(SYSDATE, hiredate))
from emp
)
You can use:
select e.*
from emp e
order by hiredate asc
fetch first 1 row only;
If you want duplicates, then add with ties.
The above works in Oracle 12C+. In earlier versions, you need a subquery:
select e.*
from (select e.*,
row_number() over (order by hiredate) as seqnum
from emp e
) e
where seqnum = 1;
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
I'm working on one SQL query.
Table name: employees.
I want to get the MAX and MIN sal with their employee names in SQL.
I know how to do with either MAX or MIN. But how can we do it both in one query?
I need a single row output like below:
e1.name AS MaxName, MAX(e1.sal) AS MaxSalary, e2.name AS MinName, MIN(e2.sal) AS MinSalary
In a single select:
SELECT MIN( salary ) AS MinSalary,
MIN( name ) KEEP ( DENSE_RANK FIRST ORDER BY salary ASC ) AS MinName,
MAX( Salary ) AS MaxSalary,
MAX( name ) KEEP ( DENSE_RANK LAST ORDER BY salary ASC ) AS MaxName
FROM Employees;
Two ways:
Using Analytic function:
SQL> SELECT MIN(ename) KEEP (DENSE_RANK FIRST ORDER BY sal) min_name,
2 MIN(sal) AS min_sal,
3 MAX(ename) KEEP (DENSE_RANK LAST ORDER BY sal) AS max_name,
4 MAX(sal) AS max_sal
5 FROM emp;
MIN_NAME MIN_SAL MAX_NAME MAX_SAL
---------- ---------- ---------- ----------
SMITH 800 KING 5000
Using an In-line view:
SQL> WITH DATA AS
2 ( SELECT MIN(sal) min_sal, MAX(sal) max_sal FROM emp
3 )
4 SELECT
5 (SELECT e.ename FROM DATA t, emp e WHERE e.sal = t.min_sal AND ROWNUM =1
6 ) min_name,
7 (SELECT t.min_sal FROM DATA t, emp e WHERE e.sal = t.min_sal AND ROWNUM =1
8 ) min_sal,
9 (SELECT e.ename FROM DATA t, emp e WHERE e.sal = t.max_sal AND ROWNUM =1
10 ) max_name,
11 (SELECT t.max_sal FROM DATA t, emp e WHERE e.sal = t.max_sal AND ROWNUM =1
12 ) max_sal
13 FROM dual;
MIN_NAME MIN_SAL MAX_NAME MAX_SAL
---------- ---------- ---------- ----------
SMITH 800 KING 5000
Assuming that you are using Oracle, try this. Here first we are getting rownumber in ascending and descending order and then doing a cross join.
with employee(id,name,sal) as
(select 1,'a',1000 from dual union all
select 3,'c',1500 from dual union all
select 2,'b',2000 from dual) --temp table to recreate the scenario
, enew as(
select e.*,row_number() over (order by sal) as salasc,row_number() over (order by sal desc) as saldesc from employee e
) --temp table to find the rownumber in ascending and descending order
--original query
select * from (select id as minsalid,name as minsalempname,sal as minsal from enew
where salasc=1)
cross join
(select id as maxsalemp,name as maxsalempname,sal as maxsal from enew
where saldesc=1)
The following solution works for MySQL, which was one of the tags you originally had when you posted your question.
You can perform a CROSS JOIN of the employees table against itself to find the max name/salary with a query which finds the min name/salary.
SELECT e1.name AS MaxName, MAX(e1.sal) AS MaxSalary,
e2.name AS MinName, MIN(e2.sal) AS MinSalary
FROM employees e1 CROSS JOIN employees e2
Click the link below for a running demo. I actually include the name/salary pairs, though you can remove the names if you don't want them there.
SQLFiddle
Try something like:
select max(sal), min(sal), employee_id
from employees
group by employee_id;
After that you can join it to get the name. Maybe you can group by name and id too.
I want to Display department number, names and salaries of employees who are earning max salary in their departments which are in the same table.
I am using oracle sql. The Table structure I am using is
Emp(Empno,Ename,Job,Salary,Deptno)
I have read about this and I think that this can be done by the use of correlated sub-queries. The query I fired was
select E1.Ename,E1.Ename,E1.Salary
from Emp E1
where E1.Empno=(
select Empno
from Emp E2
where Salary=(
select max(Salary)
from Emp
where Deptno=E1.Deptno
)
);
This gives an error saying "single-row subquery returns more than one row".
What am I doing wrong? What should do to correct it?
SELECT EmpNo, Ename,Job,Salary,Deptno
FROM
(
SELECT EmpNo, Ename,Job,Salary,Deptno,
DENSE_RANK() OVER (PARTITION BY DeptNo
ORDER BY Salary DESC ) rn
FROM Emp
) a
WHERE a.rn = 1
DENSE_RANK
or by using MAX
SELECT a.*
FROM Emp a
INNER JOIN
(
SELECT DeptNo, MAX(Salary) Max_sal
FROM Emp
GROUP BY DeptNo
) b ON a.DeptNo = b.DeptNo AND
a.Salary = b.Max_SAL
There are 2 tables available
EMP(empname PK, empno, sal, comm, deptno, hiredate, job, mgr)
DEPT(depnto, dname, loc)
The queries are
a)Display the ename and dname who is earning the first highest salary
They have given a statement this has to be done using only subqueries and Join
So i started like this:
select A.ename, B.dname from emp A, dept B where A.deptno=B.deptno
and i tried various perm&comb, but i couldn't get the join statement...
This is not a homework problem, i am just trying to solve the exercise problem given in my textbook..Thanks in advance
To get the record with the max salary I've Ordered by e.sal DESC. This will order the records in terms of salary, with the highest at the top (DESC = Descending, and therefore highest-lowest).
Then I've used TOP 1 to only return 1 record.
To get the dname I've joined the tables relating the 2 deptno columns.
SELECT TOP 1 e.empname
,d.dname
FROM [EMP] e
JOIN [DEPT] d ON d.deptno=e.deptno
ORDER BY e.sal DESC
I hope this helps
You can try following query:
SELECT emp.ename,dept.dname FROM emp
JOIN dept ON emp.deptno=dept.deptno
WHERE emp.sal=(SELECT MAX(sal) FROM emp)