ID FirstName LastName Gender Salary
1 Ben Hoskins Male 70000
2 Mark Hastings Male 60000
4 Ben Hoskins Male 70000
8 John Stanmore Male 80000
While running the query:
select *
from Employees
where Salary > (SELECT AVG(distinct SALARY) FROM employees)
It is displaying 2 records for 7000 it should display one. Why is it showing 2 records if I have used distinct?
You have used distinct the subquery, not in the outer query, so the outer query still sees the data with the duplicates.
You could solve this using:
select e.FirstName, e.LastName, e.Gender, e.Salary
from Employees e
where e.Salary > (SELECT AVG(distinct e2.SALARY) FROM employees e2);
However, something seems seriously wrong with the data model if you have rows with such duplicates. The data should be fixed.
In the meantime, you can work around the problem. You can phrase your query using a CTE that eliminates the duplicates:
with e as (
select e.*
from (select e.*,
row_number(). over (partition by firstname, lastname, gender order by id desc) as seqnum
from employees e
)
where seqnum = 1
)
select e.*
from e
where e.salary > (select avg(salary) from e)
It looks like you have duplicate rows in the table (that only differ by their id), so I am going to assume that you want distinct over the name, gender and salary rather than the salary only.
You seem to want distinct both in the outer and inner query:
select distinct firstname, lastname, gender, salary
from employees
where salary > (
select avg(salary)
from (
select distinct firstname, lastname, gender, salary
from employees
) e
)
If your database supports window functions, this can be shortened:
select *
from (
select e.*, avg(salary) over() as avg_salary
from (
select distinct firstname, lastname, gender, salary
from employees
) e
) e
where salary > avg_salary
Could someone help me how to count the number of times an employee
"id" is next to the another employee in the "executive" column?
In the first picture I am sending the table and the results I want. In the second picture the result I have
SELECT id_employee, lastname, COUNT(id_employee)
FROM employees
WHERE id_employee IN (SELECT executive FROM employees)
GROUP BY lastname, id_employee;
1
2
You need a self-join:
select iemp.d_employee, emp.last_name, subordinates
from employee as emp
join
( -- count per executive
select executive, count(*) as subordinates
from employee
group by executive
) as emp_count
on emp.id_employee = emp_count.executive
When you switch to an Outer Join you can include employees which are not executives:
select id_employee, last_name,
coalesce(subordinates, 0) -- to get zero instead of NULL
from employee as emp
left join
( -- count per executive
select executive, count(*) as subordinates
from employee
group by executive
) as emp_count
on emp.id_employee = emp_count.executive
You can try below query, simple and sweet.
SELECT * INTO #EMPLOYEE FROM
(SELECT 1001 as ID_EMP,'JAMES' as LASTNAME,NULL as EXECUTIVE
UNION
SELECT 1002 as ID_EMP,'JENSEN' as LASTNAME,1001 as EXECUTIVE
UNION
SELECT 1003 as ID_EMP,'RUDY' as LASTNAME,1001 as EXECUTIVE
UNION
SELECT 1004 as ID_EMP,'CZARNY' as LASTNAME,1002 as EXECUTIVE
UNION
SELECT 1005 as ID_EMP,'RAMBUS' as LASTNAME,1002 as EXECUTIVE
UNION
SELECT 1006 as ID_EMP,'ADAM' as LASTNAME,1003 as EXECUTIVE
)A
SELECT ID_EMP,A.COUNT FROM (SELECT EXECUTIVE,COUNT(*) AS COUNT FROM #EMPLOYEE GROUP BY EXECUTIVE)A LEFT JOIN #EMPLOYEE E
ON E.ID_EMP = A.EXECUTIVE
I have a table Employee with fields dept, employee ans salary. I want a query to list Department wise highest salaries and name of the employee with that salary.
I know it is simple. I googled but found answers like this, which lists only the department and salary
SELECT dept, SUM (salary)
FROM employee
GROUP BY dept;
SELECT e1.*
FROM employee e1
JOIN (SELECT dept, MAX(salary) FROM employee GROUP BY dept) e2 ON
e1.dept = e2.dept AND e1.salary = e2.salary
SQL Server 2008 supports Window Functions which help you get what you want.
WITH recordList
AS
(
SELECT dept, employeeName, salary,
DENSE_RANK() OVER (PARTITION BY dept ORDER BY salary DESC) rn
FROM employee
)
SELECT dept, employeeName, salary
FROM recordList
WHERE rn = 1
SQLFiddle Demo
TSQL Ranking Function
SELECT e.*, d.deptname
FROM employee e
JOIN department d ON e.deptid = d.deptid
WHERE EXISTS (SELECT 1
FROM employee e_in
JOIN department d_in ON e_in.deptid = d_in.deptid
WHERE d_in.deptid = d.deptid
GROUP BY d_in.deptid
HAVING MAX(e_in.salary) = e.salary)
This will do it.
SELECT E1.DEPT, E2.ENAME, E1.HIGHEST_SALARY
FROM
(SELECT DEPT, MAX(SALARY) HIGHEST_SALARY
FROM EMPLOYEE
GROUP BY DEPT) E1
INNER JOIN EMPLOYEE E2 ON E1.HIGHEST_SALARY = E2.SALARY
AND E1.DEPT = E2.DEPT
select * from (select salary,last_name,dense_rank()
over (order by salary desc)
sal_rank from employees) where sal_rank <=3;
That's all... this is the output below:
SALARY LAST_NAME SAL_RANK
---------- ------------------------- ----------
24000 King 1
17000 Kochhar 2
17000 De Haan 2
14000 Russell 3
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: