How to fetch rows with MAX condition involving multiple columns - sql

I have an Employee table with the following columns:
Emp_Id
Emp_Name
ProjectName
ProjectStartDate
ProjectEndDate
Emp_ManagerId
Every employee can work in multiple projects at the same time.
I want the fetch all the records in the table for each employee with max ProjectStartDate. If an employee has multiple records with same ProjectStartDate then the record with max ProjectEndDate should be returned.
All dates in MM/DD/YYYY

You can use ROW_NUMBER() in a subquery to rank the records of each employee by descending project start and end date, and then filter on the top record of each employee in the outer query:
SELECT *
FROM (
SELECT
e.*,
ROW_NUMBER() OVER(PARTITION BY Emp_Id ORDER BY ProjectStartDate DESC, ProjectEndDate DESC) rn
FROM Employee e
) x
WHERE rn = 1

You can use the ROW_NUMBER() function, as in:
select *
from (
select
*,
row_number() over(partition by emp_id
order by projectstartdate desc, projectenddate desc) as rn
from employee
) x
where rn = 1

Related

Write SQL & Hive query to print the year in which the 2nd highest salary was paid for each country?

Write SQL and HIVE query to print the year in which the 2nd highest salary was paid for each country?.
Please provide query for the below table
country,salary,year
india,1000,2017
japan,2000,2017
germany,1500,2017
india,1250,2018
japan,500,2018
china,955,2017
japan,850,2019
china,1150,2018
india,1250,2019
something like:
select
t.*
from (
select
tbl.*,
row_number() over(partition by country order by salary desc) rn
from
tbl
) t
where
t.rn = 2
The big question is how you handle ties. Presumably, you mean the second highest distinct salary. In that case, you are specifically looking for the dense_rank() window function:
select t.*
from (select t.*,
dense_rank() over (partition by country order by salary desc) as seqnum
from t
) t
where t.seqnum = 2;
Now, the challenge with this is that it could return more than one row in the event of ties. If you specifically want one row, then:
select t.*
from (select t.*,
dense_rank() over (partition by country order by salary desc) as ranking,
row_number() over (partition by country, salary order by country) as seqnum
from t
) t
where t.ranking = 2 and seqnum = 1;

Select only one employee from every department

I want one employee from every department (EmpDepartment), for example in my table there are:
3 employees with EmpDepartment 1
2 employees with EmpDepartment 2 and
1 Employee with EmpDepartment 3
I want EmployeeId, EmployeeName and EmpDepartment of any one employee from each separate department.
Use a windowing function like this:
SELECT *
FROM (
SELECT
E.*,
ROW_NUMBER() OVER (PARTITION BY EmpDepartment) AS RN
FROM Employee
) X
WHERE X.RN = 1
You can add an order clause the the windowing function if you have a business rule that you want to use in picking the employee
eg
ROW_NUMBER() OVER (PARTITION BY EmpDepartment order by EmployeeId) AS RN
This will get a random employee from each department due to ordering by NEWID()...
SELECT * FROM
(
SELECT EmployeeID, EmployeeName, EmployeeEmail
, ROW_NUMBER() OVER (PARTITION BY EmpDepartment ORDER BY NEWID()) AS rn
FROM dbo.Employee
) x
WHERE x.rn = 1
You can change the order by clause to something else if you want to.
This will return the employee from each department having the minimum EmployeeID in that department (since it is not important which employee will be in the results):
SELECT e.* FROM Employee e
WHERE NOT EXISTS (
SELECT 1 FROM Employee
WHERE EmpDepartment = e.EmpDepartment AND EmployeeID < e.EmployeeID
)
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 1
UNION
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 2
UNION
SELECT Top(1) EmployeeID, EmployeeName, EMPDeptartment FROM Employee WHERE EmpDetpartment = 3
You can either use rownumber to find any employee of a particular dept change rn to any value as 1,2,...etc
Select department, employee
from (
Select department, employee,
row_number() over (partition by department order by employee) rn
)
where rn =1;
or use simple group by
Select department, max(employee)
from table
group by department

fetch equal number of rows for the given categories

My SQL table design is:
id,
name,
department,
status,
value
The ask is to fetch equal number of records from each department. Maximum number of rows allowed per fetch is restricted to 100 rows. Assume that there are 4 distinct departments (A,B,C and D) in the table. For each department there are few hundred records. So, the query should fetch only 25 records for each department. And if the distinct department size is three than the split should be 100/3.
I used the below query. But it is not calculating the number of rows for each department dynamically. Currently I have used 25 a constant value.
SELECT *
FROM (
SELECT dept.*,
ROW_NUMBER() OVER( PARTITION BY dept.department
ORDER BY dept.department, dept.id ) deptEntry
FROM TABLE_NAME dept
) dept
WHERE dept.deptEntry <=25
AND dept.status='ACTIVE'
AND rownum <=100;
Count the number of distinct departments and then divide your number of rows by that value:
SELECT *
FROM (
SELECT dept.*,
ROW_NUMBER() OVER( PARTITION BY department
ORDER BY department, id ) AS deptEntry,
COUNT( DISTINCT department ) OVER () AS num_dept
FROM TABLE_NAME dept
) dept
WHERE dept.deptEntry <= 100 / num_dept
AND dept.status='ACTIVE'
AND rownum <=100;
Updated:
SELECT *
FROM (
SELECT dept.*,
ROW_NUMBER() OVER( PARTITION BY department
ORDER BY id ) AS deptEntry
FROM TABLE_NAME dept
WHERE status = 'ACTIVE'
ORDER BY deptEntry, department
) dept
WHERE ROWNUM <=100;

Finding department having maximum number of employee

I have a table employee
id name dept
1 bucky shp
2 name shp
3 other mrk
How can i get the name of the department(s) having maximum number of employees ? ..
I need result
dept
--------
shp
SELECT cnt,deptno FROM (
SELECT rank() OVER (ORDER BY cnt desc) AS rnk,cnt,deptno from
(SELECT COUNT(*) cnt, DEPTNO FROM EMP
GROUP BY deptno))
WHERE rnk = 1;
Assuming you are using SQL Server and each record representing an employee. So you can use window function to get the result
WITH C AS (
SELECT RANK() OVER (ORDER BY dept) Rnk
,name
,dept
FROM table
)
SELECT TOP 1 dept FROM
(SELECT COUNT(Rnk) cnt, dept FROM C GROUP BY dept) t
ORDER BY cnt DESC
With common table expressions, count the number of rows per department, then find the biggest count, then use that to select the biggest department.
WITH depts(dept, size) AS (
SELECT dept, COUNT(*) FROM employee GROUP BY dept
), biggest(size) AS (
SELECT MAX(size) FROM depts
)
SELECT dept FROM depts, biggest WHERE depts.size = biggest.size
Based on one of the answer, Let me try to explain step by step
First of all we need to get the employee count department wise. So the firstly innermost query will run
select count(*) cnt, deptno from scott.emp group by deptno
This will give result as
Now out of this we have to get the one which is having max. employee i.e. department 30.
Also please note there are chances that 2 departments have same number of employees
The second level of query is
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
Now we have assigned ranking to each department
Now to select rank 1 out of it. we have a simplest outer query
select * from
(
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
)
where rnk=1
So we have the final result where we got the department which has the maximum employees. If we want the minimum one we have to include the department table as there are chances there is a department which has no employees which will not get listed in this table
You can ignore the scott in scott.emp as that is the table owner.
The above SQL can be practised at Practise SQL online

Top 2 Salary Grouped By Department

Below is the table I am referring to.
I want to find ou the 2 Employees in each department with highest salary.
Further to the above answer, if there are ties (multiple employees sharing the same salary), you can use the following to bring them all through instead of just picking two at random (which is what the ROW_NUMBER clause will do)
SELECT *
FROM (
SELECT *, DENSE_RANK() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2
Use ROW_NUMBER() to get the top salaries per Department, then select the first two records from each departmental partiton:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rn
FROM MyTable ) t
WHERE t.rn <= 2