I have a table EmpDetails
:
DeptID EmpName Salary
Engg Sam 1000
Engg Smith 2000
HR Denis 1500
HR
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.
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
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.
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.
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?
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.