SQL query for highest netpay among the employees - sql

SQL query to display employees records whose netpay is greater than any other employee. Display name,salary,commission,netpay and manager name.
Exclude if manager name is null.
Netpay=salary+commission.
Table:
employees -- commission, dep_id, emp_id, emp_name, hire_date, job_name, manager_id, salary
This is my query:
SELECT e.emp_name, e.salary, e.commission, (e.salary+e.commission) AS netpay, x.emp_name
FROM employees e
INNER JOIN employees x ON x.emp_id = e.manager_id
WHERE (e.salary+e.commission) = (SELECT MAX(salary+commission) FROM employees where manager_id IS NOT NULL);
I'm not getting the test cases cleared for the above query. can any one help me out to solve this.
employee table
The output I'm getting is
emp_name
salary
commission
netpay
manager
Tucker
1600
7000
8600
blaze
I think this the max value among the records but still i have no idea whats the problem with this getting solved.
I am adding the create table and some insert commands:
CREATE TABLE employees(emp_id number, emp_name varchar2(25), job_name varchar2(25), manager_id number, hire_date date, salary number, commission number, dep_id number) ;
INSERT INTO employees VALUES(68319,'kayling', 'president', null, 11/18/1991,6000,3100,1001);
INSERT INTO employees VALUES(66928,'blaze', 'manager', 68319,5/1/1991,2750,3200,3001);
INSERT INTO employees VALUES(68454,'tucker', 'salesman', 66928,9/8/1991,1600,7000,3001);
INSERT INTO employees VALUES(65646,'clare', 'manager', 68319, 5/9/1991,2550,2300,1001);
INSERT INTO employees VALUES(67858,'scarlet', 'analyst', 65646, 1/11/1991,3100,520,2001);

Get the max value and then find the employee(s) matching that pay. ie:
SELECT e.emp_name, e.salary, e.commission, (e.salary+e.commission) AS netpay
FROM employees e
where (e.salary + +coalesce(e.commission,0)) = (Select max(salary+coalesce(commission,0)) from Employees where manager_id is not null) and
manager_id is not null;
EDIT: This is with manager name:
SELECT e.emp_name, e.salary, e.commission, (e.salary+e.commission) AS netpay, x.emp_name as Manager
FROM employees e
inner join employees x on e.manager_id = x.emp_id
where (e.salary + +coalesce(e.commission,0)) = (Select max(salary+coalesce(commission,0)) from Employees where manager_id is not null);
SQL fiddle link

You can use a hierarchical query to get the manager's name (without having read the table twice) and you can use FETCH FIRST ROW WITH TIES to get the people with the highest net salary:
SELECT emp_name,
salary,
commission,
salary + commission AS netpay,
PRIOR emp_name AS manager_name
FROM employees
WHERE manager_id IS NOT NULL
START WITH manager_id IS NULL
CONNECT BY PRIOR emp_id = manager_id
ORDER BY netpay DESC
FETCH FIRST ROW WITH TIES;
Which, for your sample data, outputs:
EMP_NAME | SALARY | COMMISSION | NETPAY | MANAGER_NAME
:--------| -----: | ---------: | -----: | :-----------
tucker | 1600 | 7000 | 8600 | blaze
db<>fiddle here

Select
e.emp_name as "name",
e.salary as "salary",
e.commission as "commission",
nvl2(e.commission,e.salary+e.commission,e.salary) as "netpay",
x.emp_name as "Manager name"
from (employees e inner join employees x on e.manager_id = x.emp_id)
where nvl2(e.commission,e.salary+e.commission,e.salary) > any (select nvl2(commission,salary+commission,salary) from employees) and x.emp_name is not null ;

SELECT
e.emp_name,
e.salary,
e.commission,
e.salary+e.commission NETPAY,
m.emp_name
FROM employees e
INNER JOIN employees m ON e.manager_id = m.emp_id
WHERE e.salary+e.commission > ANY (SELECT salary+commission FROM
employees) ;

You might be missing a trick here in the question asked. The expected result could be "greater than any other employee". This could also mean return those employees who have at least one employee having lesser netpay!! Late, but hope it helps! Enjoy!
select e1.emp_name,
e1.salary,
e1.commission,
e1.salary+e1.commission as netpay,
e2.emp_name as manager_name
from employees e1
join employees e2 on e1.manager_id = e2.emp_id
where e1.salary+e1.commission not in (
select min(salary+commission)
from employees where manager_id is not null);

Related

Analytic functions and plain SQL equivalent

I'm using Oracle and SQL Developer. I have downloaded HR schema and need to do some queries with it. Now I'm working with table Employees. As an user I need to see the list of employees with lowest salary in each department. I need to provide different solutions by means of plain SQL and one of analytic functions. About analytic functions, I have used RANK():
SELECT *
FROM
(SELECT
employee_id,
first_name,
department_id,
salary,
RANK() OVER (PARTITION BY department_id
ORDER BY salary) result
FROM
employees)
WHERE
result = 1
AND department_id IS NOT NULL;
The result seems correct:
but when I try to use plain SQL I actually get all employees with their salaries.
Here is my attempt with GROUP BY:
SELECT
department_id, MIN(salary) AS "Lowest salary"
FROM
employees
GROUP BY
department_id;
This code seems good, but I need to also get columns first_name and employee_id.
I tried to do something like this:
SELECT
employee_id,
first_name,
department_id,
MIN(salary) result
FROM
employees
GROUP BY
employee_id,
first_name,
department_id;
and this:
SELECT
employee_id,
first_name,
salary,
departments.department_id
FROM
employees
LEFT OUTER JOIN
departments ON (employees.department_id = departments.department_id)
WHERE
employees.salary = (SELECT MIN(salary)
FROM departments
WHERE department_id = employees.department_id)
These seem wrong. How can I change or modify my queries to get the same result as when I'm using RANK() by means of plain SQL (two solutions at least)?
One of the options could be like here (with old EMP table)...
SELECT EMPNO, ENAME, DEPTNO, SAL
FROM EMP e
WHERE SAL = (Select MIN_SAL From (SELECT DEPTNO, Min(SAL) "MIN_SAL"
FROM EMP
GROUP BY DEPTNO)
Where DEPTNO = e.DEPTNO)
ORDER BY DEPTNO, SAL;
Second option could be...
SELECT EMPNO, ENAME, DEPTNO, SAL
FROM (SELECT e.EMPNO, e.ENAME, e.DEPTNO, e. SAL, (Select Min(SAL) "MIN_SAL" From EMP Where DEPTNO = e.DEPTNO) "MIN_SAL" From EMP e)
WHERE SAL = MIN_SAL
ORDER BY DEPTNO, SAL;
Regards...
You can use a subquery to find the lowest salary per employee and use the main query to only show the information of those employees that are selected by this subquery:
SELECT
employee_id,
first_name,
department_id,
salary
FROM employees e1
WHERE salary =
(SELECT MIN(e2.salary)
FROM employees e2
WHERE e1.employee_id = e2.employee_id);
This will produce exactly the same outcome as your query with RANK.
I think it would make sense to apply some sorting which is missing in your query. I don't know how you want to sort, but here an example to sort by the employee's name:
SELECT
employee_id,
first_name,
department_id,
salary
FROM employees e1
WHERE salary =
(SELECT MIN(e2.salary)
FROM employees e2
WHERE e1.employee_id = e2.employee_id)
ORDER BY first_name;
Since you asked for at least two solutions, let's have a look on another option:
SELECT
e1.employee_id,
e1.first_name,
e1.department_id,
e1.salary
FROM employees e1
JOIN (
SELECT employee_id, MIN(salary) salary
FROM employees
GROUP BY employee_id ) e2
ON e1.employee_id = e2.employee_id AND e1.salary = e2.salary
ORDER BY first_name;
As you can see, this differs since the sub query will apply a GROUP BY clause and it can be successfully executed as own query which is not possible for the sub query used in the previous query.
The JOIN to the main query will then make sure to get again the desired result.
Here are some options to get the employees with the minimum salary in their department:
With MIN (salary) OVER (...)
select employee_id, first_name, department_id, salary
from
(
select e.*, min(salary) over (partition by department_id) as min_sal
from employees e
)
where sal = min_sal;
With RANK and FETCH FIRST
select *
from employees
order by rank() over (partition by department_id order by salary)
fetch first row with ties;
With IN
select *
from employees
where (department_id, salary) in
(
select department_id, min(salary)
from employees
group by department_id
);
With NOT EXISTS
select *
from employees e
where not exists
(
select null
from employees other
where other.department_id = e.department_id
and other.salary < e.salary
);
If you will only ever have one person with the minimum salary per department then you can use KEEP:
SELECT department_id,
MIN(employee_id) KEEP (DENSE_RANK FIRST ORDER BY salary) AS employee_id,
MIN(first_name) KEEP (DENSE_RANK FIRST ORDER BY salary, employee_id) AS first_name,
MIN(salary) AS min_salary
FROM employees
GROUP BY department_id
Which, for the sample data:
CREATE TABLE employees (employee_id, department_id, first_name, salary) AS
SELECT 1, 1, 'Alice', 1000 FROM DUAL UNION ALL
SELECT 2, 1, 'Betty', 2000 FROM DUAL UNION ALL
SELECT 3, 2, 'Carol', 3000 FROM DUAL UNION ALL
SELECT 4, 2, 'Debra', 3000 FROM DUAL UNION ALL
SELECT 5, 2, 'Emily', 4000 FROM DUAL;
Outputs:
DEPARTMENT_ID
EMPLOYEE_ID
FIRST_NAME
MIN_SALARY
1
1
Alice
1000
2
3
Carol
3000
Note: this will not match Debra, even though she also has the lowest salary in department 2, as it will only find a single employee with the minimum salary and the minimum employee id.
If you can have multiple employees with the same minimum-per-department then you can use a correlated sub-query:
SELECT department_id,
employee_id,
first_name,
salary
FROM employees e
WHERE EXISTS(
SELECT 1
FROM employees x
WHERE e.department_id = x.department_id
HAVING MIN(x.salary) = e.salary
);
Which, for the sample data, outputs:
DEPARTMENT_ID
EMPLOYEE_ID
FIRST_NAME
SALARY
1
1
Alice
1000
2
3
Carol
3000
2
4
Debra
3000
Which does return Debra.
fiddle

SQL COUNT modify

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;

Calculate the highest salary for each department

I have to create a report which displays the highest salaries in each department.
I must have the following columns, department_id, department_name, last_name and MAX(salary). And it cannot contain any duplicates.
I have managed to get a query result with all the columns however due to the last_name column I have a query result as the following.
90, Executive, De Haan, 17000
90, Executive, Kochhar, 17000
80, Sales, Tucker, 10000
80, Sales, Bernstein, 9500
80, Sales, Hall, 9000
Obviously, the highest in the Executive department is 17000, and 10000 in Sales. I need to display only 1 salary amount for each department. Any ideas on how I achieve this?
Below is what I typed into SQL to get this result.
SELECT DISTINCT department_id, department_name, last_name, MAX(salary)
FROM employees
NATURAL JOIN departments
GROUP BY department_id, department_name, last_name
ORDER BY MAX(salary) DESC;
So you need to find the max salary per department id then join back to the employee table to pull the last name. Something like this:
SELECT sub.department_id, sub.department_name, emp.last_name, sub.max_sal
FROM
(SELECT e.department_id, d.department_name, MAX(e.salary) AS max_sal
FROM employees e
INNER JOIN departments d
ON e.department_id = d.department_id
GROUP BY e.department_id, d.department_name) sub
INNER JOIN employees emp
ON sub.department_id = emp.department_id
AND sub.max_sal = emp.salary
Note that this solution would show multiple people if they have the same salary and it's the highest for their department.

sorting table based on a condition

i have to sort the employees in the EMPLOYEE table by the following rule: when their department is SALES, sort by experience, otherwise sort by SALARY
this is what i have tried :
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE from employee
where dept_id=(select dept_id from department where name='SALES') order by HIRE_DATE asc;
UNION
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE from employee
where dept_id NOT IN (select dept_id from department where name='SALES') order by salary desc;
which throws an error because of two orders i think. Any solutions?
try this:
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE from employee E
join department D
on E.dept_id=D.dept_id
order by (case when D.name='SALES' then HIRE_DATE end),
(case when D.name<>'SALES' then salary end) desc
Sales department is displayed first, sorted by hire_date. Other departments are displayed next ordered by salary.
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE
from employee
inner join department
on employee.dept_id = department.dept_id
order by
-- Sales department is on top. Swap 0 and 1 if you want sales on bottom
case when department.name = 'SALES'
then 0
else 1
end,
-- And employees are sorted by hire_date
case when department.name = 'SALES'
then employee.HIRE_DATE
else null
end,
-- Employees from other departments are sorted by salary
employee.Salary desc
use decode:
SELECT fname || ' ' || lname AS emp_name
,salary
,hire_date
FROM employee e
,department d
WHERE e.dept_id = d.dept_id
ORDER BY decode(d.name,'SALES',experience,salary)
;
see also http://sqlfiddle.com/#!4/afa6f/1
SELECT e.fname||' '||e.lname as emp_name, e.salary, e.hire_date
FROM employee e, department d
WHERE e.dept_id = d.dept_id
ORDER BY
CASE
WHEN d.name ='SALES' then
hire_date ASC
ELSE
salary DESC
END
OK. Apologies, try this - probably been answered already tho.

Highest Salary in each department

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: