SQL display maximum 2 employees hired the latest in 2021 per department - sql

A SQL Server database has 2 tables:
Department: Id
Employee: Id, Department, Employee_Name, Date_Hired
I wanted to display maximum 2 employees hired the latest in 2021 per department
For example
The output should be
I have this SQL:
SELECT e.*
FROM Employee e
WHERE e.Date_Hired IN (SELECT e.Date_Hired
FROM Employee e
WHERE YEAR(e.Date_Hired) = 2021)
ORDER BY e.Date_Hired DESC
But it is displaying all 3 items from department 1.
Thanks in advance!

SELECT e.*
FROM Employee e,
(SELECT id,
Date_Hired,
row_number() OVER(PARTITION BY Department ORDER BY id DESC) AS rn
FROM Employee e
WHERE YEAR (e.Date_Hired) = 2021) sub
WHERE rn <= 2
and e.id = sub.id
ORDER by e.Date_Hired DESC

If your relation had integer rank numbers
describing each employee's position within a department,
then a simple WHERE clause could easily request the top K employees.
So you are looking for the rank query function:
https://learn.microsoft.com/en-us/sql/t-sql/functions/rank-transact-sql?view=sql-server-ver16
The relationship among RANK, DENSE_RANK, and ROW_NUMBER is
perhaps more subtle than your unit tests and future maintainers
would care to consider.

Related

Why doesn't DISTINCT work in this case? (SQL)

SELECT DISTINCT
employees.departmentname,
employees.firstname,
employees.salary,
employees.departmentid
FROM employees
JOIN (
SELECT MAX(salary) AS Highest, departmentID
FROM employees
GROUP BY departmentID
) departments ON employees.departmentid = departments.departmentid
AND employees.salary = departments.highest;
Why doesn't the DISTINCT work here?
I'm trying to have each department to show only once because the question is asking the highest salary in each department.
Use the ROW_NUMBER() function, as in:
select departmentname, firstname, salary, departmentid
from (
select e.*,
row_number() over(partition by departmentid, order by salary desc) as rn
from employees e
) x
where rn = 1
I'm trying to have each department to show only once because the question is asking the highest salary in each department.
Use window functions:
SELECT e.*
FROM (SELECT e.*,
ROW_NUMBER() OVER (PARTITION BY departmentID ORDER BY salary DESC) as seqnum
FROM employees e
) e
WHERE seqnum = 1;
This is guaranteed to return one row per department, even when there are ties. If you want all rows when there are ties, use RANK() instead.
Why doesn't the DISTINCT work here?
DISTINCT is not a function; it is a keyword that will eliminate duplicate rows when ALL the column values are duplicates. It does NOT apply to a single column.
The DISTINCT keyword has "worked" (i.e. done what it is intended to do) because there are no rows where all the column values are a duplicate of another row's values.
However, it hasn't solved your problem because DISTINCT is not the correct solution to your problem. For that, you want to "fetch the row which has the max value for a column [within each group]" (as per this question).
Gwen, Elena and Paula all have the same salary
and they are in the same department

SQL Server Group Records Based Another Columns

I am working on a table that contains employee data. The table has historical employee records based on department and year as follows:
Now I want to consolidate records based on EmployeeId, Department and get the Min FromYear and Max ToYear like this:
I tried to use a query :
Select EmployeeId, Department, MIN(FromYear), MAX(ToYear)
from Employee
GROUP BY EmployeeId, Department
But this query fails for the employee with ID 3 as it returns me only 2 rows:
I have added a similar structure and query here: http://sqlfiddle.com/#!9/6f1e53/5
Any help would be highly appreciated!
This is a gaps-and-islands problem. Identify the islands using lag() and a cumulative sum. Then aggregate:
select employeeid, department, min(fromyear), max(toyear)
from (select e.*,
sum(case when prev_toyear >= fromyear - 1 then 0 else 1 end) over (partition by employeeid order by fromyear) as grp
from (select e.*,
lag(toyear) over (partition by employeeid, department order by fromyear) as prev_toyear
from employee e
) e
) e
group by employeeid, department, grp
order by employeeid, min(fromyear);
Here is a db<>fiddle.
you can use self join as well
select a.employeeid, min(a.fromyear), max(b.toyear) from emp a
inner join emp b on a.employeeid=b.employeeid
group by a.employeeid

SQL Query with two WHERE conditions

My task is:
To make a query which will get Employees, who earn the biggest salary for their working experience. In other words, the Employee who earns the biggest salary with the biggest experience.
As I consider, I need to make a query with two conditions:
select * from employee where salary in (select max(salary) from employee) and
hire_date in (select min(hire_date) from employee)
I think this was what you're trying to do:
select * from (
select *,
datediff(day,hire_date,getdate()) [Days_Worked],
dense_Rank() over(Partition by datediff(day,hire_date,getdate()) order by salary desc) [RN]
from employee
)a
where a.RN = 1
order by Days_Worked DESC
So that'll give you a list of employees with the highest salary against the employees that have worked the same number of days.
Just note that with dense rank if for example there are 2 employees that have worked 88 days and both earn $50000 (higher than anyone else) it will list both employees, use ROW_NUMBER() instead of DENSE_RANK() if you want to restrict examples like that to 1 employee.
If I get it correctly, this query solves your problem.
SELECT TOP 1 WITH TIES * FROM
employee
ORDER BY
hire_date ASC,
salary DESC

To display the name of the department that has the least student count in SQL

Tables:
Department (dept_id,dept_name)
Students(student_id,student_name,dept_id)
I am using Oracle. I have to print the name of that department that has the minimum no. of students. Since I am new to SQL, I am stuck on this problem. So far, I have done this:
select d.department_id,d.department_name,
from Department d
join Student s on s.department_id=d.department_id
where rownum between 1 and 3
group by d.department_id,d.department_name
order by count(s.student_id) asc;
The output is incorrect. It is coming as IT,SE,CSE whereas the output should be IT,CSE,SE! Is my query right? Or is there something missing in my query?
What am I doing wrong?
One of the possibilities:
select dept_id, dept_name
from (
select dept_id, dept_name,
rank() over (order by cnt nulls first) rn
from department
left join (select dept_id, count(1) cnt
from students
group by dept_id) using (dept_id) )
where rn = 1
Group data from table students at first, join table department, rank numbers, take first row(s).
left join are used is used to guarantee that we will check departments without students.
rank() is used in case that there are two or more departments with minimal number of students.
To find the department(s) with the minimum number of students, you'll have to count per department ID and then take the ID(s) with the minimum count.
As of Oracle 12c this is simply:
select department_id
from student
group by department_id
order by count(*)
fetch first row with ties
You then select the departments with an ID in the found set.
select * from department where id in (<above query>);
In older versions you could use RANK instead to rank the departments by count:
select department_id, rank() over (order by count(*)) as rnk
from student
group by department_id
The rows with rnk = 1 would be the department IDs with the lowest count. So you could select the departments with:
select * from department where (id, 1) in (<above query>);

How to write a query to get the latest employee record given the effective date in oracle?

I have a employee and employee_history table. For every update on employee table, I insert a record into the employee_history table.
Both the tables have a column called as effective date which indicates that the employee status as on that effective date.
Below are my two tables.
I need to get the employee record latest as on that effective date.
e.g If I need to get the employee as on 16 may I should get the emp_hist_id = 2 record from history table. As on 5 june I should get the emp_hist_id = 4 from hist table.
And as on 15th August I should get the record from employee table itself.
Please help.
You could try something like
SELECT * FROM (
SELECT * FROM (
(SELECT emp_id, name, email, title, region, division, "effective date"
FROM employee
WHERE emp_id = desired_id)
UNION
(SELECT emp_id, name, email, title, region, division, "effective date"
FROM employee _history
WHERE emp_id = desired_id)
) t
WHERE t."effective date" <= desired_date
ORDER by t."effective date" DESC) p
WHERE ROWNUM = 1
The idea is to take records related to desired user from both tables, then take dates lower than desired one and finally catch the first
You can solve this problem without analytic functions. The subquery here calculates the most recent effective date in the history record before the employee effective date:
select e.*
from employee_history eh join
(select e.employee_id, max(eh.effective_date) as latest_effective_date
from employee e join
employee_history eh
on e.employee_id = eh.employee_id and
e.effective_date >= eh.effective_date
) ehl
on eh.employee_id = ehl.employee_id and
eh.effective_date = ehl.effective_date
This solution assumes that there are no duplicate effective dates in the history table. If there are, then you have another option. Assuming the employee_history_ids are assigned sequentially, take the max of that id instead of the date.
There are alternative formulations of the solution using Oracle's analytic functions.
Try the following :
SELECT *
FROM
(SELECT e.emp_id,
e.name,
e.email,
e.title,
e.region,
e.division,
e.effective_date,
row_number() over (partition BY e.emp_id
ORDER BY e.effective_date DESC) rn
FROM employee e
UNION ALL
SELECT eh.emp_id,
eh.name,
eh.email,
eh.title,
eh.region,
eh.division,
eh.effective_date,
row_number() over (partition BY eh.emp_id
ORDER BY eh.effective_date DESC) rn
FROM employee_history eh)
WHERE effective_date < to_date('15/06/2012','DD/MM/YYYY')
AND rn = 1
you can see a better example here