From the SQL Oracle HR scheme I used the folowing:
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2)
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID
ORDER BY DEPARTMENT_ID
To get:
DEPARTMENT_ID ROUND(AVG(SALARY),2)
10 4400
20 9500
30 4150
40 6500
50 3475,56
60 5760
...
How do I change it so: it only count the departments that have the max avg salary (in my case 1) and show also the max avg salary?
Thank you for your time!
If I understood you, this is one possible way:
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
AND ROUND(AVG(SALARY),2) = (
SELECT MAX(T.AVG_SALARY)
FROM (
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID) AS T)
GROUP BY DEPARTMENT_ID
ORDER BY DEPARTMENT_ID
This will show you ALL THE DEPARTMENTS that have max avg salary. If you want only the count:
SELECT COUNT(A.*), AVG(A.AVG_SALARY)
FROM (
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID) A
WHERE A.AVG_SALARY = (
SELECT MAX(T.AVG_SALARY) AS MAX_AVG_SALARY
FROM (
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID) AS T)
Another way that should work, using joins:
SELECT t1.DEPARTMENT_ID, ROUND(AVG(t1.SALARY),2) AS AVG_SALARY
FROM EMPLOYEES t1
LEFT JOIN (SELECT MAX(AVG_SALARY) AS MAX_AVG_SALARY FROM EMPLOYEES) t2
ON AVG_SALARY=t2.MAX_AVG_SALARY
WHERE t1.DEPARTMENT_ID IS NOT NULL
AND AVG_SALARY=t2.MAX_AVG_SALARY
ORDER BY t1.DEPARTMENT_ID ASC;
I tested the idea on a sample table of mine using oracle, and on a w3schools sql testing page with this code:
SELECT Customers.CustomerName, Orders.maxid
FROM Customers
LEFT JOIN (select max(Orders.CustomerID) as maxid from Orders) orders
ON Customers.CustomerID=Orders.maxid
where customers.customername is not null and customers.customerid=orders.maxid
ORDER BY orders.maxid desc;
It should grab only the departments that match their average salary with the max average salary that was selected in the join statement.
If you are only looking for the count of the departments, and not a list of the department names, then this slight modification should work for you:
SELECT COUNT(t1.DEPARTMENT_ID) as Num_Of_Depts, ROUND(AVG(t1.SALARY),2) AS AVG_SALARY
FROM EMPLOYEES t1
LEFT JOIN (SELECT MAX(AVG_SALARY) AS MAX_AVG_SALARY FROM EMPLOYEES) t2
ON AVG_SALARY=t2.MAX_AVG_SALARY
WHERE t1.DEPARTMENT_ID IS NOT NULL
AND AVG_SALARY=t2.MAX_AVG_SALARY
GROUP BY AVG_SALARY;
I am learning database query and want to find out the following SQL query from the HR Schema in Oracle database.
Find number of employees in each salary group. Salary groups are considered as follows.
Group 1: 0k to <5K, 5k to <10k, 10k to <15k, and so on.
what will be the possible query code ??
Tables are as follows: There are seven tables in total
REGIONS: REGION_ID, REGION_NAME
COUNTRIES: COUNTRY_ID, COUNTRY_NAME, REGION_ID
LOCATIONS: LOCATION_ID, STREET_ADDRESS, POSTAL_CODE, CITY, STATE_PROVINCE, COUNTRY_ID
DEPARTMENTS: DEPARTMENT_ID, DEPARTMENT_NAME, MANAGER_ID, LOCATION_ID
EMPLOYEES: EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB_ID, SALARY, COMMISSION_PCT, MANAGER_ID, DEPARTMENT_ID
JOB_HISTORY: EMPLOYEE_ID, START_DATE, END_DATE, JOB_ID, DEPARTMENT_ID
JOBS: JOB_ID, JOB_TITLE, MIN_SALARY, MAX_SALARY
I first use a common table expression (CTE) to calculate the different groups using a case statement...
WITH CTE AS (
SELECT Emp_ID,
case when salary >= 0 salary < 5000 then "<5K"
when salary >= 5000 and salary < 10000 then "<10k"
when salary >= 10000 and salary < 15000 then "<15k"
else "UDF" end as SalaryGroup
FROM Employees)
SELECT count(Emp_ID) as Cnt, SalaryGroup
FROM CTE
GROUP BY SalaryGroup;
I then select from that table to give you the counts by the salary group calculated.
select trunc(salary/5000,00) e,
count(*)
from EMPLOYEES
group by trunc(SALARY/5000,0)
ORDER by e asc
I have a table EmpDetails:
DeptID EmpName Salary
Engg Sam 1000
Engg Smith 2000
HR Denis 1500
HR Danny 3000
IT David 2000
IT John 3000
I need to make a query that find the highest salary for each department.
SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID
The above query is the accepted answer but it will not work for the following scenario. Let's say we have to find the employees with the highest salary in each department for the below table.
DeptID
EmpName
Salary
Engg
Sam
1000
Engg
Smith
2000
Engg
Tom
2000
HR
Denis
1500
HR
Danny
3000
IT
David
2000
IT
John
3000
Notice that Smith and Tom belong to the Engg department and both have the same salary, which is the highest in the Engg department. Hence the query "SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID" will not work since MAX() returns a single value. The below query will work.
SELECT DeptID, EmpName, Salary FROM EmpDetails
WHERE (DeptID,Salary) IN (SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID)
Output will be
DeptID
EmpName
Salary
Engg
Smith
2000
Engg
Tom
2000
HR
Danny
3000
IT
John
3000
Assuming SQL Server 2005+
WITH cteRowNum AS (
SELECT DeptID, EmpName, Salary,
DENSE_RANK() OVER(PARTITION BY DeptID ORDER BY Salary DESC) AS RowNum
FROM EmpDetails
)
SELECT DeptID, EmpName, Salary
FROM cteRowNum
WHERE RowNum = 1;
If you want to show other parameters too along with DeptId and Salary like EmpName, EmpId
SELECT
EmpID
, Name,
, Salary
, DeptId
FROM Employee
where
(DeptId,Salary)
in
(select DeptId, max(salary) from Employee group by DeptId)
SELECT empName,empDept,EmpSalary
FROM Employee
WHERE empSalary IN
(SELECT max(empSalary) AS salary
From Employee
GROUP BY EmpDept)
Select empname,empid,Sal,DeptName from
(Select e.empname,e.empid,Max(S.Salary) Sal,D.DeptName, ROW_NUMBER() Over(partition by D.DeptName order by s.salary desc) Rownum
from emp e inner join Sal S
on e.empid=s.empid
inner join Dept d on e.Deptid=d.Deptid
group by e.empname,e.empid,D.DeptName,s.Salary
) x where Rownum = 1
This will work if the department, salary and employee name are in the same table.
select ed.emp_name, ed.salary, ed.dept from
(select max(salary) maxSal, dept from emp_dept group by dept) maxsaldept
inner join emp_dept ed
on ed.dept = maxsaldept.dept and ed.salary = maxsaldept.maxSal
Is there any better solution than this?
ermn, something like:
select
d.DeptID,
max(e.Salary)
from
department d
inner join employees e on d.DeptID = e.DeptID
group by
d.DeptID
WITH cteRowNum AS (
SELECT DeptID, EmpName, Salary,
ROW_NUMBER() OVER(PARTITION BY DeptID ORDER BY Salary DESC) AS RowNum
FROM EmpDetails
)
SELECT DeptID, EmpName, Salary,Rownum
FROM cteRowNum
WHERE RowNum in(1,2);
SELECT Employee_ID
, First_name
, last_name
, department_id
, Salary
FROM (SELECT Employee_ID
, First_name
, last_name
, department_id
, Salary
, MAX(salary) OVER (PARTITION BY department_id) dept_max_sal
FROM EMPLOYEES) AS Emp
WHERE salary = dept_max_sal;
Use following command;
SELECT A.*
FROM #EmpDetails A
INNER JOIN ( SELECT DeptID ,
MAX(salary) AS salary
FROM #EmpDetails
GROUP BY DeptID
) B ON A.DeptID = B.DeptID
AND A.salary = B.salary
ORDER BY A.DeptID
SELECT DeptID, MAX(Salary)
FROM EmpDetails
GROUP BY DeptID
This query will work fine, but the moment if you want to fetch some others details related to the employee having the highest salary will contradict.
You can use :
SELECT DepatID, a , b, c
FROM EmpDetails
WHERE Salary IN (
SELECT max(Salary)
FROM EmpDetails
GROUP BY DeptID
);
if you will use the previous query it will only reflects the records of the min val except the salary as you have used the max function.
SELECT
DeptID,
Salary
FROM
EmpDetails
GROUP BY
DeptID
ORDER BY
Salary desc
***
> /*highest salary by each dept*/
***
select d.Dept_Name,max(e.salary)
from emp_details as e join Dept_Details as d
on e.d_id=d.Dept_Id
group by d.Dept_Name
select distinct e.d_id,d.Dept_Name
from emp_details as e join Dept_Details as d
on e.d_id=d.Dept_Id
select e.salary,d.Dept_Name,d.Dept_Id
from emp_details as e join Dept_Details as d
on e.d_id=d.Dept_Id
/////simplest query for max salary dept_wise////
Use the below quesry:
select employee_name,salary,department_id from emp where salary in(select max(salary) from emp group by department_id);
select empno
from EMP e
where salary=(select max(sal)
from EMP w
where groupby w.deptno having e.deptno=w.deptno)
I hope it will work...
Use correlated subquery:
SELECT DeptID, EmpName, Salary
FROM EmpDetails a
WHERE Salary = (SELECT MAX(Salary)
FROM EmpDetails b
WHERE a.DeptID = b.DeptID)
This is the best possible solution for ORACLE:
Select * from (select customerid, city, freight,
row_number() over (partition by customerid order by freight desc) Row_Number from
(select orders.orderId, customers.CUSTOMERID, customers.city, orders.FREIGHT from orders inner join customers on orders.customerid = customers.customerid where customers.country='Germany' order by customers.customerid, orders.freight desc)
order by customerid, freight desc) where Row_Number<=2;
Notice here I have used partition by clause for marking row number, this is majorly because we need to partition the records grouping them according to customer id. I have used two inner queries here. The inner most query is to give a view which is sorted according to customer ID and decreasing order of cost. Now from that we need to obtain always top two records so firstly we need to name them and then we need to filter them according to rownum. Second level query is to mark rownum according to customer ID. And final query will filter the result according to rownum. For every partition.
select deptid, empname, salary from
(Select deptid, empname,salary,
rank() Over(Partition by deptid order by salary desc)as rank from
EmpDetails) emp
where emp.rank = 1
First ranks each employee by salary in descending order having highest
rank 1 and then selects only deptid, empname, salary. You can do this for
all Nth member of the group.
SELECT empname
FROM empdetails
WHERE salary IN(SELECT deptid max(salary) AS salary
FROM empdetails
group by deptid)
select a.*
from EmpDetails a
inner join
(
select DeptID,max(Salary) as Salary
from EmpDetails group by DeptID
)b
on a.DeptID = b.DeptID and a.Salary = b.Salary
Here is a way to get maximum values and names on any version of SQL.
Test Data:
CREATE TABLE EmpDetails(DeptID VARCHAR(10), EmpName VARCHAR(10), Salary DECIMAL(8,2))
INSERT INTO EmpDetails VALUES('Engg','Sam',1000)
INSERT INTO EmpDetails VALUES('Engg','Smith',2000)
INSERT INTO EmpDetails VALUES('HR','Denis',1500)
INSERT INTO EmpDetails VALUES('HR','Danny',3000)
INSERT INTO EmpDetails VALUES('IT','David',2000)
INSERT INTO EmpDetails VALUES('IT','John',3000)
Example:
SELECT ed.DeptID
,ed.EmpName
,ed.Salary
FROM (SELECT DeptID, MAX(Salary) MaxSal
FROM EmpDetails
GROUP BY DeptID)AS empmaxsal
INNER JOIN EmpDetails ed
ON empmaxsal.DeptID = ed.DeptID
AND empmaxsal.MaxSal = ed.Salary
Not the most elegant, but it works.
SELECT D.DeptID, E.EmpName, E.Salary
FROM Employee E
INNER JOIN Department D ON D.DeptId = E.DeptId
WHERE E.Salary IN (SELECT MAX(Salary) FROM Employee);
select * from (
select a.* from EmpDetails a
right join (select DeptID,max(salary) as Salary from EmpDetails group by DeptID) b
on b.DeptID=a.DeptID and b.salary=a.salary ) as c group by c.DeptID;
The below query will display employee name with their respective department name in which that particular employee name is having highest salary.
with T as
(select empname, employee.deptno, salary
from employee
where salary in (select max(salary)
from employee
group by deptno))
select empname, deptname, salary
from T, department
where T.deptno=department.deptno;
I executed the above query successfully on Oracle database.
If you just want to get the highest salary from that table, by department:
SELECT MAX(Salary) FROM TableName GROUP BY DeptID
IF you want Department and highest salary, use
SELECT DeptID, MAX(Salary) FROM EmpDetails GROUP BY DeptID
if you want more columns in employee and department, use
select Department.Name , emp.Name, emp.Salary from Employee emp
inner join (select DeptID, max(salary) [salary] from employee group by DeptID) b
on emp.DeptID = b.DeptID and b.salary = emp.Salary
inner join Department on emp.DeptID = Department.id
order by Department.Name
if use salary in (select max(salary...)) like this, one person have same salary in another department then it will fail.
The below listed query will list highest salary in each department.
select deptname, max(salary) from department, employee where
department.deptno=employee.deptno group by deptname;
I executed this query successfully on Oracle database.
with ctesal as (
select DepartmentId , Name , Salary, ROW_Number() OVER (partition by DepartmentId
order by Salary desc) as RowNum
from dbo.Employee
)
select DepartmentId , Name , Salary , RowNum from ctesal where RowNum =2;
This is applicable to SQL server.
ROW_Number is a inbuilt function in SQL server .It gives count starting from 1 based on partition by and order by clause. At the end, We can write where condition based on our requirements.
I have like 2 approaches using one with Rank and the other with ROW_NUMBER
This is my sample data
Age Name Gender Salary
----------- -------------------------------------------------- ---------- -----------
1 Mark Male 5000
2 John Male 4500
3 Pavan Male 5000
4 Pam Female 5500
5 Sara Female 4000
6 Aradhya Female 3500
7 Tom Male 5500
8 Mary Female 5000
9 Ben Male 6500
10 Jodi Female 7000
11 Tom Male 5500
12 Ron Male 5000
13 Ramani Female 7000
So here is my first query to find max salary and the person with that max salary for each Gender
with CTE as(
select RANK() over(partition by Gender Order by Salary desc) as [Rank],* from employees)
select * from CTE where [Rank]=1
Rank Age Name Gender Salary
-------------------- ----------- -------------------------------------------------- ---------- -----------
1 10 Jodi Female 7000
1 13 Ramani Female 7000
1 9 Ben Male 6500
So in this case, we can see there is a tie between these 2 female employees "Jodi" and "Ramani". In that case, As a tie-breaker I want to make use of Age as a deciding factor and person with more age is supposed to be displayed
with CTE as(
select RANK() over(partition by Gender Order by Salary desc,age desc) as [Rank],* from employees)
select * from CTE where [Rank]=1
Rank Age Name Gender Salary
-------------------- ----------- -------------------------------------------------- ---------- -----------
1 13 Ramani Female 7000
1 9 Ben Male 6500
Usually, in this case for finding the highest salary, it doesn't make much difference even if
Rank, Dense_Rank, or Row_Number() are used. But they have some impact in other cases.
Thank you #JoeStefanelli for his answer (https://stackoverflow.com/a/8477083/4691279). He provided SQL Server 2005+ version and I used the same to create the Oracle version:
WITH cteRowNum(dep_id, emp_id, Salary, RowNums) AS (
SELECT dep_id, emp_id, Salary,
DENSE_RANK() OVER(PARTITION BY dep_id ORDER BY Salary DESC) AS RowNums
FROM employee
)
SELECT cteRowNum.dep_id, cteRowNum.emp_id, cteRowNum.Salary
FROM cteRowNum
WHERE cteRowNum.RowNums = 1;
You can test this using livesql.oracle.com, below are my DDLs and DMLs you can use:
create table employee (
emp_id varchar2(50) NOT NULL,
dep_id varchar2(50) NOT NULL,
salary number not null
);
create table department (
dep_id varchar2(50) NOT NULL,
dep_name varchar2(50) NOT NULL
);
insert into employee values (100, 5000, 1000000);
insert into employee values (200, 5000, 2000000);
insert into employee values (300, 5000, 3000000);
insert into employee values (400, 6000, 1500000);
insert into employee values (500, 6000, 1500000);
insert into employee values (600, 7000, 1000000);
insert into employee values (700, 7000, 1000000);
insert into employee values (800, 7000, 2000000);
insert into department values (5000, 'dep 1');
insert into department values (6000, 'dep 2');
insert into department values (7000, 'dep 3');
And below is the success screenshot of the query: