The Employee table holds all employees. Every employee has an Id, a salary, and there is also a column for the department Id.
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Jim | 90000 | 1 |
| 3 | Henry | 80000 | 2 |
| 4 | Sam | 60000 | 2 |
| 5 | Max | 90000 | 1 |
+----+-------+--------+--------------+
The Department table holds all departments of the company.
+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+
Write a SQL query to find employees who have the highest salary in each of the departments. For the above tables, your SQL query should return the following rows (order of rows does not matter).
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| IT | Jim | 90000 |
| Sales | Henry | 80000 |
+------------+----------+--------+
My solution is below, Someone please tell me why this is not working
Select Department , Employee ,MAX(Salary) AS SALARY FROM
(select Department.Name AS Department,Employee.Name as Employee, SALARY from employee
LEFT JOIN Department
ON Employee.DepartmentID=Department.ID) as base
GROUP BY Department
The difference between my code output and expected output is given below.
Output
{"headers": ["Department", "Employee", "SALARY"], "values": [["IT", "Joe", 90000], ["Sales", "Henry", 80000]]}
Expected
{"headers": ["Department", "Employee", "Salary"], "values": [["IT", "Jim", 90000], ["Sales", "Henry", 80000], ["IT", "Max", 90000]]}
Someone please tell me why this is not working
Because what you have so far reads like this: "for every department, return an unspecified employee, and also return max salary within this department". Note that max salary is in no way related to the employee that is returned. In this case, it's seems to be returning the first employee for each department. And in case of "Sales", it even turns out to be correct, accidentally.
What you should have written is "for every department, find out its max salary. Then find all employees whose salary is equal to max_salary for their department"
You first need to get the MAX(SALARY) by Department and then query all employee that have this salary in this department.
-- max salary by department, adding DepartmentName to the result
WITH max_salary as (
SELECT Department.DepartmentId, Department.Name as DptName, MAX(SALARY)
FROM Employee JOIN Department
ON Employee.DepartmentID=Department.ID
GROUP BY DepartmentId, Name
)
-- select ALL employees with max salary
SELECT DptName, e.Name, e.SALARY
FROM Employee e JOIN max_salary m
ON e.SALARY=m.SALARY AND e.DepartmentId=m.DepartmentId
Get the highest SALARY for each department, and then return the employees whose salaries are equal to the maximum SALARY. The following query does this.
WITH TB_Salary as (
SELECT MAX(SALARY) AS Salary,DepartmentId
FROM employee
GROUP BY DepartmentId
)
SELECT DISTINCT Department.Name AS Department,employee.Name AS Employee,employee.Salary FROM employee
JOIN TB_Salary ON employee.SALARY = TB_Salary.SALARY AND employee.DepartmentId = TB_Salary.DepartmentId
JOIN Department ON Department.Id = employee.DepartmentId
ORDER BY employee.Salary DESC
OR
SELECT DISTINCT Department.Name AS Department,employee.Name AS Employee,employee.Salary
FROM employee
JOIN
(
SELECT MAX(SALARY) AS Salary,DepartmentId
FROM employee
GROUP BY DepartmentId
) TB_Salary
ON employee.SALARY = TB_Salary.SALARY AND employee.DepartmentId = TB_Salary.DepartmentId
JOIN Department ON Department.Id = employee.DepartmentId
ORDER BY employee.Salary DESC
output:
Related
I have three tables: Employee, Employer, and Employment History. I'm looking to get a list of employees, with their most recent full-time employer, if they have an active full-time record.
Say I have the following Employment History table:
Employee ID | Employer ID | Start Date | End Date | Status
---------------------------------------------------------------
1 | AA | 1/1/2019 | | Part-Time
1 | BB | 1/1/2000 | | Full-Time
2 | CC | 3/1/2019 | | Part-Time
2 | DD | 3/1/2000 | 5/15/2021 | Full-Time
And Employees with IDs 1, 2, and 3.
Here's where I start:
select employee.id, employer.id
from Employee employee left join EmploymentHistory eh on eh.employeeId = employee.id
left join Employer employer on eh.employerId = employer.id
But I don't know how to say if the employee doesn't have an active employer, then give me a null employer ID. If they have an active (as in no end date) employment history record that is full-time, give me the most recent of those, and if they don't have an active full-time record, then give me the most recent part-time one.
I started going into loops with sub queries and trying to select based on max start date, and I'm all sorts of turned around.
In the end, I'd like the results to look something like this:
Employee ID | Employer ID
---------------------------
1 | BB |
2 | CC |
3 | <null> |
Is this possible?
You can try OUTER APPLY and a subquery that fetches the top record for each employee according to the type and end of the employment.
SELECT e.id,
x.employerid
FROM employee e
OUTER APPLY (SELECT TOP 1
eh.employerid
FROM employmenthistory eh
WHERE eh.employeeid = e.id
AND eh.status IN ('Full-Time',
'Part-Time')
ORDER BY eh.status ASC,
eh.enddate DESC) x;
I'm looking to get a list of employees, with their most recent full-time employer, if they have an active full-time record.
You can just use one table:
select eh.*
from (select eh.*,
row_number() over (partition by employee_id order by startdate desc) as seqnum
from EmploymentHistory eh
where status = 'Full-Time'
) eh
where seqnum = 1;
I have a problem - here is my Employee table:
Name | Department | Salary
------+-------------+-------------
Ram |IT | 1000
Shyam |HR | 2000
Sita |Management | 5000
Joe |IT | 6000
Lacy |HR | 2000
Gen |Management | 4000
Maria |IT | 2000
Antony|HR | 3000
Raman |Management | 50000
Now I want the result like this:
Department | Salary |
-------------+------------+
IT | 20000
HR | 30000
Management | 50000 | *
Where * will be used to mark the max salary from any department. I've tried many unsucessful attempts, like :
Select
Salary,
Case
When Salary = Max(Salary) Then '*'
End
From
tblEmployees
Group By
Salary
You want a window function:
Select Department, max(Salary) as salary,
(case When max(Salary) = max(Max(Salary)) over ()
Then '*'
End)
from tblEmployees
group by department;
The IT department in your result should be 6000.
select Department,
salary = max_sal_dep,
highest_salary = IIF(max_sal_dep = max_sal_all, '*', null)
from
(
select Department,
max_sal_all = MAX(Salary) over (),
max_sal_dep = MAX(Salary) over (partition by Department order by Department),
the_row = row_number () over (partition by Department order by Salary desc)
from #t
) x where x.the_row = 1
order by x.max_sal_dep;
I have two tables
Student
StudentId | StudentName
---------- | --------------
1 | John
2 | Susan
3 | Andy
4 | Joe
Department
StudentId | DepartmentId
---------- | ------------
1 | 123
1 | 234
2 | 123
2 | 456
3 | 123
4 | 456
Each student can be in multiple departments but I have to find those students which are only in one department like student 3 and 4
Any help?
Use GROUP BY and HAVING
SELECT s.StudentId,s.StudentName
FROM Department d
JOIN Student s ON s.StudentId=d.StudentId
GROUP BY s.StudentId,s.StudentName
HAVING COUNT(d.DepartmentId)=1
And if you also want to show students which not in Department table
SELECT s.StudentId,s.StudentName
FROM Department d
RIGHT JOIN Student s ON s.StudentId=d.StudentId
GROUP BY s.StudentId,s.StudentName
HAVING COUNT(d.DepartmentId)<=1
Variant with LEFT JOIN
SELECT s.StudentId,s.StudentName
FROM Student s
LEFT JOIN Department d ON s.StudentId=d.StudentId
GROUP BY s.StudentId,s.StudentName
HAVING COUNT(d.DepartmentId)<=1
Try this,
SELECT st.StudentId, St.StudentName
FROM student st
JOIN Department dep ON dep.StudentId = st.StudentId
GROUP BY st.StudentId
HAVING COUNT(dep.DepartmentId) = 1;
You can use IN with department table group by StudentId alongwith having count(Student_Id) = 1 in sub-query as below.
SELECT *
FROM student s
WHERE s.StudentId IN (
SELECT d.StudentId
FROM Department d
GROUP BY d.StudentId
HAVING count(d.DepartmentId) = 1
);
Result:
+-----------+-------------+
| studentid | studentname |
+-----------+-------------+
| 3 | Andy |
| 4 | Joe |
+-----------+-------------+
DEMO
Simply join them & aggregate them by Group by clause with having.. count() function
SELECT s.StudentId, s.StudentName
FROM student s
JOIN Department d ON d.StudentId = s.StudentId
GROUP BY s.StudentId, s.StudentName
HAVING COUNT(d.DepartmentId) = 1;
Result :
studentid studentname
3 Andy
4 Joe
Another approach is to eliminate the students having multiple departments at the beginning by using a cte table, then use the table with IN keyword like:
with cte as (
select StudentId
from Department
group by StudentId
having count(StudentId)=1
)
select *
from Students
where StudentId in (select StudentId from cte)
I need your help to write two SQL queries (DB Oracle) to fetch data. Both table has huge data so need to take care of the performance also. Below is the scenario -
There are two tables Department (DEPT) and Employee (EMP). They have a 1 (DEPT) : M (EMP) relationship.
Department table has columns
Row_id, DeptNm, Created_date
Employee table has columns
Row_id, EMPName, Emp_num, Par_row_id (FK to DEPT.row_Id), Salary
For a specific Department, sort data per employee's decreasing salary and rank it. Data should be shown like this:
DeptNm | EmpNm | Salary | Rank
--------------------------------
Finance | Vikram | 200000 | 1
Finance | Uttaam | 150000 | 2
Finance | Rajeev | 100000 | 3
ITDPPT | Balaajii | 150000 | 1
ITDEPT | Harsha | 120000 | 2
ITDEPT | Weeniji | 100000 | 3
Query that to show the data highest salary for a department. Data should be as -
Dept_Nm | EMP_NM | Salary
Finance | Vikramadit | 2000000
ITDEPT | Balaji | 1500000
select *
from (
select dp.deptname,
emp.empname,
emp.salary,
dense_rank() over (partition by dp.deptname order by emp.salary desc) as rnk
from employee emp
join department dp on dp.row_id = emp.par_row_id
) t
where rnk = 1
Try this will help you please put Rank as I didn't get what process you want if you want dynamic Rank than try any "temp" variable.
select D.DeptName,E.EmpName,E.Salary from Employee E
lefe join Department as D on D.Par_Row_Id=E.Row_Id order by E.Salaray DESC
select D.DeptName,E.EmpName,E.Salary from Employee E
left join Department as D on D.Par_Row_Id=E.Row_Id order by E.Salaray DESC
here is the situation. I have two tables, one is table Tbl_employ, second is tbl_details.
Tbl_employ
----------
id | name
1 | Ravi
2 | ram
3 | sham
4 | john
Tbl_details
-----------
id | salary | emp_id
1 | 500 | 1
2 | 200 | 2
3 | 400 | 3
4 | 501 | 4
I want to return the name of the employee who has top salary in tbl_detail.
What will be the join query for this condition?
Please suggest. Thanks in advance.
Perhaps:
SELECT TOP(1) name
FROM Tbl_employ e INNER JOIN Tbl_details d ON e.id = d.emp_id
ORDER BY d.salary DESC;
Essentially, this joins the two tables on the key fields (id and emp_id), returning only a single result (TOP(1)) that is the maximum salary row (ORDER BY d.salary DESC).
I appreciate the answer of #Max Vernon.
You can also do it by another way. Please try this
select t.name from (
select Distinct top 1 salary ,name
from Tbl_employ as E
left outer join Tbl_details as D on D.empid=E.id
order by salary desc
) as t
you can check it here SQL Fiddle