Find the third-highest salary in each department - sql-server

I am trying to find the third-highest salary in each department if there is such.
SELECT DepartmentID
FROM Employees
GROUP BY DepartmentID
This is what I can do.
I looked at similar posts but not sure I understand how to do it with my table.

You can use row_number function to assign a order of salary, then get the 3rd one:
SELECT s.DepartmentID, s.Salary
FROM (
SELECT DepartmentID, Salary, ROW_NUMBER() OVER(PARTITION BY DepartmentID ORDER BY Salary DESC) AS salary_rank
FROM Employees) s
WHERE s.salary_rank=3

SELECT e.first_name,
e.last_name,
d.department_name,
salary,
ROW_NUMBER() OVER ( PARTITION BY d.id ORDER BY salary DESC ) AS
salary_rank
FROM department d
JOIN employee e ON d.id = e.department_id
ORDER BY department_name;

Related

Top 5 Employees from each dept with lowest attendance

How do I find top 5 employees from each department with lowest attendance?
---Employee Table
--- Department Table
--- Attendance Table
I tried in this way to find top 5 salary from each department but how to apply in this specially for attendance table with employee and department table how to find top 5 employees with lowest attendance please assist me in this regard with cte.
Thanks
With ctetemp As
(
Select E.EmpId, E.Ename, E.Salary,D.Dname,
DENSE_RANK() OVER(PARTITION BY D.DeptId ORDER BY Salary desc) as rnw
from EmployeeTbl AS E JOIN Departmet AS D
ON D.DeptId = e.Dept_Id_Emp
)
Select * from ctetemp
where rnw IN (5)
You will need to reference the attendance table.
I'm assuming 'a' means 'absent' in this context.
SELECT
AbsenceSummary.DeptID
,AbsenceSummary.EmpId
,AbsenceSummary.AbsentDays
,AbsenceSummary.AbsentRank
FROM
(
SELECT
dept.DeptId
,att.EmpId
,COUNT(*) AS AbsentDays
,DENSE_RANK() OVER (PARTITION BY dept.DeptId ORDER BY COUNT(*) DESC) AS AbsentRank
FROM
attendance att
INNER JOIN
employee emp
ON emp.EmpID = att.EmpId
INNER JOIN
department dept
ON dpt.DeptId = emp.DeptId
WHERE
dept.DeptId IN (<the departments you care about>)
AND att.atdate >= <your minimum date>
AND att.atdate <= <your maximum date>
AND att.attendance = 'a' --absent
GROUP BY
dept.DeptId
,att.EmpId
) AbsenceSummary
WHERE
AbsenceSummary.AbsentRank <= 5
For the record, the AtId column in this situation is useless and possibly counterproductive. The key is (EmpId,atDate).

3rd highest salary in each department

I have the following tables: https://pastebin.com/Js0Sm69S (CREATE and INSERT statements).
I would like to find the third-highest salary in each department if there is such.
I was able to achieve this:
Using the following query:
SELECT *,
DENSE_RANK() OVER
(PARTITION BY DepartmentId ORDER BY Salary DESC) AS DRank
FROM Employees
I am not sure if DENSE_RANK() is the best ranking function to use here. Maybe not, because WHERE DRank=3 may return more than one result (but we can say TOP(1)). What do you think about this? Now how to display the third-highest salary in each department if there is such?
Try this
Select EmployeeID,FirstName,DepartmentID,Salary
From (
Select *
,RN = Row_Number() over (Partition By DepartmentID Order By Salary)
,Cnt = sum(1) over (Partition By DepartmentID)
From Employees
) A
Where RN = case when Cnt<3 then Cnt else 3 end
You're almost there, but you can achieve this with ROW_NUMBER, instead of DENSE_RANK. I think following query should help.
WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY DepartmentId ORDER BY Salary DESC) AS DRank
FROM Employees
)
SELECT *
FROM cte
WHERE DRank= 3

T-SQL Grouping Issue

I have 2 tables.
Contacts
ContactID pk
EmailAddress
FirstName
LastName
Address
Orders
OrderID pk
ContactID fk
I want to get the number or orders for each email address in Contacts like below
select
Contacts.EmailAddress,
count(distinct Orders.OrderID) AS NumOrders
from
Contacts inner join Orders on Contacts.ContactID = Orders.ContactID
group by
Contacts.EmailAddress
Problem is, I also want the first name, last name, address. But I can't group by those because each email address in Contacts could have a different first name, lastname or address associated with it.
ie:
myname#email.com, Fred, Jackson, 123 Main St
myname#email.com, Bob, Smith, 456 Spruce St.
How can I change my query so that I can get the first name, last name and address for the most recent entry made in Contacts for that email address?
Thanks in advance!
My first thought would be to use windowed functions.
SELECT EmailAddress,
FirstName,
Lastname,
[Address],
EmailOrderCount
FROM (SELECT c.EmailAddress,
c.FirstName,
c.LastName,
c.[Address],
COUNT(o.OrderID) OVER (PARTITION BY c.EmailAddress) EmailOrderCount,
ROW_NUMBER() OVER (PARTITION BY c.EmailAddress ORDER BY c.ContactID DESC) Rn
FROM Contacts c
JOIN Orders o ON c.ContactID = o.ContactID
) t
WHERE Rn = 1
Demo
another way would be to use CROSS APPLY to append the top 1 contact record to the summary rows.
SELECT c.EmailAddress,
COUNT(o.OrderID) NumOrders,
ca.FirstName,
ca.LastName,
ca.[Address]
FROM Contacts c
INNER JOIN Orders ON c.ContactId = o.ContactID
CROSS APPLY (
SELECT TOP 1
FirstName,
Lastname,
[Address]
FROM Contacts c2
WHERE c2.EmailAddress = c.EmailAddress
ORDER BY c2.ContactID DESC) ca
GROUP BY c.EmailAddress,
ca.FirstName,
ca.LastName,
ca.[Address]
Try this:
select
Contacts.Name,
Contacts.FirstName,
Contacts.LastName
Contacts.EmailAddress,
count(distinct Orders.OrderID) AS NumOrders
from
(
select max(ContactID) as ContactID,
EmailAddress
from Contacts
group by EmailAddress
) MinContactForEachEMailAddress
inner join
Contacts
on MinContactForEachEMailAddress.ContactID = Contacts.ContactID
inner join
Orders
on Contacts.ContactID = Orders.ContactID
group by
Contacts.EmailAddress
Another way to get what you want is using a CTE and taking the "maximum" row by using ROW_NUMBER.
;WITH CTE AS (
SELECT C.ContactId, C.Name, C.FirstName, C.LastName, C.EmailAddress,
ROW_NUMBER() OVER (PARTITION BY EmailAddress ORDER BY ContactId DESC) RowNo
FROM Contact C
)
SELECT CTE.*, COUNT(o.OrderID) OVER (PARTITION BY CTE.EmailAddress) Cnt
FROM CTE
JOIN Orders O on CTE.ContactID = O.ContactID
-- select the "maximum" row
WHERE CTE.RowNo = 1
An easy way to do this is to make your original query a subquery and select from it. I'm making a slight change, because it's a better practice to group by your primary key than your email address. (Is it a safe bet that each contact has just one email address, and that the basic intent is to group by person?) If so, try this:
SELECT DISTINCT c.EmailAddress, c.FirstName, c.LastName, c.Address, sub.NumOrders
FROM
(
select
Contacts.ContactID
count(distinct Orders.OrderID) AS NumOrders
from
Contacts inner join Orders on Contacts.ContactID = Orders.ContactID
group by
Contacts.ContactID
) sub
JOIN Contacts c
ON sub.ContactID = c.ContactID
If you really need to group by email address instead, then change the above subquery to your original query and change c.EmailAddress to sub.EmailAddress. Of course you may order the SELECT fields however best suits you.
Edit follows:
The ContactID must be a sequence number and you can continually put the same person in the table. So if you add the DISTINCT keyword in the outer query I believe that will give you what you need.

T-Sql query for the situation - Need a departmentID with max number of employees?

let's say employee table has employee details and deptId of the employee.
to get the number of employees in each deptid,
select deptId, COUNT(*) from employee group by deptId;
question is: to get the deptId having max number of employees of the above result set,
select Top 1 deptId, COUNT(*) from employee group by deptId order by 2 desc
(2-ref to second column in the query list) - will do.. but
Is there anyway to avoid ordering this set? or better way of writing this sql,
thanks
If you just want the MAX number of employees within a department, you can do this:
SELECT TOP 1 DepartmentID,
COUNT(EmployeeID)
FROM EmployeeTable
GROUP BY DepartmentID
ORDER BY COUNT(EmployeeID) DESC
Without any ordering, it is hard, but try
Select deptId, cnt
From (Select deptId, count(*) cnt
from employee
Group By deptId) Z
Where cnt = (Select Max(cnt)
From (Select deptId, count(*) cnt
From employee
Group By deptId) ZZ)

How to get the highest paid employee row

A table consists of employee name, address, phone, department, salary:
How to get the highest paid employee row from each department?
I tried with
select dept, max(salary) from employee group by dept
but it gives only two columns. But I want to select an entire row. How to do it?
Alternatively how to add more columns to the result?
(I am using SQL Server 2008)
You simply need to join the query you currently have back to the employee table to get the full employee information.
select e.*
from employee e
inner join (select dept, max(salary) ms from employee group by dept) m
on e.dept = m.dept and e.salary = m.ms
SELECT name,
address,
phone,
department,
salary,
dept
FROM (SELECT name,
address,
phone,
department,
salary,
dept,
row_number() OVER(PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employee) AS e
WHERE e.rn = 1
Using row_number() will give you one row if there is a tie for the highest salary. If you want all the highest salaries for each department you should use rank() instead.
SELECT name,
address,
phone,
department,
salary,
dept
FROM (SELECT name,
address,
phone,
department,
salary,
dept,
rank() OVER(PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employee) AS e
WHERE e.rn = 1
Something like this?
select * from employee where salary = (select max(salary) from employee)
with cte as (
select *, rank() over (partition by dept order by salary desc) as [r]
from employees
)
select * from cte where [r] = 1;
select * from employee
where salary in
(select max(salary) from employee group by dept);
If situation like you have both employee details and department in same table and you have to find the highest paid employee from each department like given below
EmployeeId EmployeeName Department Salary
1 Neeraj Dot Net 45000
2 Ankit Java 5000
3 Akshay Java 6000
4 Ramesh Dot Net 7600
5 Vikas Java 4000
7 Neha Php 8500
8 Shivika Php 4500
9 Tarun Dot Net 9500
Then you can solve it by using below solutions
Solution - 1
SELECT t.EmployeeName,t.Department,t.Salary
FROM(SELECT MAX(Salary) AS TotalSalary,Department FROM Employee GROUP BY Department)
AS TempNew Inner Join Employee t ON TempNew.Department=t.Department
and TempNew.TotalSalary=t.Salary
ORDER BY t.Department ASC
Solution -2
;WITH EmployeeDetails AS (
SELECT EmployeeName, Department, DENSE_RANK() OVER(PARTITION BY Department
ORDER BY Salary DESC) AS SalaryRank, Salary FROM Employee )
SELECT EmployeeName, Department, Salary FROM EmployeeDetails WHERE SalaryRank=1
OUTPUT
EmployeeName Department Salary
Neeraj Dot Net 45000
Akshay Java 6000
Neha Php 8500

Resources