Nested query sql hospital - sql

enter image description here
select Fname,Lname,salary,ssn
from Employee
where joptype='nurse' AND salary <= ALL (select salary
from Employee E,Nurses N
where E.Ssn=N.Ssn AND E.joptype='nurse' AND N.shift='morning')
I want to return a list of nurses name who works at morning and their salary is less than all nurses, or the opposite. I've tried both morning and night, also I've tried greater than all nurses. I think the problem is in the second where it seems like he ignores the shift condition.

You can use EXISTS to find the morning shifts and, from Oracle 12, you can use ORDER BY salary ASC FETCH FIRST ROW WITH TIES to find the matching employees with the lowest salary:
SELECT Fname,
Lname,
salary,
ssn
FROM Employee e
WHERE jobtype='nurse'
AND EXISTS( SELECT 1
FROM Nurses N
WHERE E.Ssn=N.Ssn
AND N.shift='morning' )
ORDER BY salary ASC
FETCH FIRST ROW WITH TIES;
or, if you want to check all nurses and find the minimum salary and then filter on morning shifts:
SELECT *
FROM (
SELECT Fname,
Lname,
salary,
ssn
FROM Employee
WHERE jobtype='nurse'
ORDER BY salary ASC
FETCH FIRST ROW WITH TIES
) e
WHERE EXISTS( SELECT 1
FROM Nurses N
WHERE E.Ssn=N.Ssn
AND N.shift='morning' )
If you want to use a JOIN, rather than EXISTS, then you can use:
SELECT e.Fname,
e.Lname,
e.salary,
e.ssn
FROM (
SELECT Fname,
Lname,
salary,
ssn
FROM Employee
WHERE jobtype='nurse'
ORDER BY salary ASC
FETCH FIRST ROW WITH TIES
) e
INNER JOIN Nurses N
ON E.Ssn=N.Ssn
WHERE N.shift='morning'
(However, if there are multiple entries in Nurses for an Employee then you will get duplicates using a JOIN that you would not get using EXISTS)
Or for your code, you appear to have the filter for shifts in the wrong place:
SELECT e.Fname,
e.Lname,
e.salary,
e.ssn
FROM Employee e
INNER JOIN Nurses n
ON (e.Ssn = n.Ssn)
WHERE e.jobtype='nurse'
AND n.shift='morning'
AND e.salary <= ALL ( SELECT salary
FROM Employee
WHERE jobtype='nurse' );
fiddle

This is how I understood it; what you said:
their salary is less than all nurses
probably means their average salary, so I used it in a subquery.
select e.fname, e.lname, e.salary, e.ssn
from employee e join nurse n on e.ssn = n.ssn
where e.joptype = 'nurse'
and n.shift = 'morning'
and salary < (select avg(salary) --> average salary of all nurses
from employee
where joptype = 'nurse'
);
(Just a remark: is it really joptype? Is it not a job?)

Maybe you could try it like here:
select
Fname, Lname, salary, ssn
from
Employee
where
joptype='nurse' AND
salary <= ( Select MIN(salary)
From Employee E
Inner join Nurses N ON(E.Ssn=N.Ssn)
Where E.joptype = 'nurse' AND
N.shift = 'morning'
)
... this will give you the list of nurses with salary less than or equal to the minimum salary among morning nurses..

Related

Query to display employees with lowest salary from each department

I want to display the lowest earning employees of each department based on salary using min().
I have tables of employees with id, first name, last name, department id, salary
and departments, department_id, name department id from 1 to 5.
I am having trouble doing this, I only know how to start
SELECT name, surname from employees WHERE...
You would use min() for this. You would use window functions:
select e.*
from (select e.*,
rank() over (partition by department_id order by salary) as seqnum
from employees e
) e
where seqnum = 1
order by department_id;
With rank()over() ranking window function you can have your rows within a group ranked as you wish. Here we have ranked all the employees starting with lowest salary in a department. Now if we select rows with rn =1 then it will select employees from a department with lowest salary.
Then joined the result with department table to get the name of the
With lowestEarningEmployees as
(
id, first_name, last_name, department_id, salary, rank()over(partition by department_id order by salary)rn from employees
)
select le.id, le.first_name, le.last_name, le.department_id,d.name, le.salary,
from lowestEarningEmployees le inner join departments d on le.department_id=d.department_id
** If more than one employee in a department have lowest salary all of them will be selected. If you want to select only one employee with lowest salary then you need to use row_number() instead of rank().
You can also use subquery to have your desired result (Though I would suggest to use first one) :
Select e.id, e.first_name, e.last_name, e.department_id, d.name, e.salary
from employees e inner join department d on e.department_id = d.department_id
where e.salary=(select min(salary) from employees empl where e.department_id=empl.department_id)

I want to select the employees from my employees able (I named it ANGAJATI) who has the salary > avg(salary) of their department

In the employees table I have id_departament
And I can`t figure it out how to extract the avg salary for every employee
Use window functions if your RDBMS supports them:
select *
from (
select e.*, avg(salary) over(partition by id_department) avg_salary_dept
from employee e
) t
where salary > avg_salary_dept
Alternatively, you can join the table with an aggregate query that computes the average salary per department:
select e.*
from employee e
inner join (
select id_department, avg(salary) avg_salary_dept
from employee
group by id_department
) a on e.id_department = a.id_department and e.salary > a.avg_salary_dept

How to retrieve highest salary for each department across employees?

I am trying to compile a query which gives me the highest salary per each department and for each unique employee. The complexity is that 1 employee can be part of multiple departments.
In case the same employee has the highest salary in several departments, only the department with a lower salary should show. This is my start but I am not sure how to continue from here:
select max(salary) as salary, dd.dept_name,d.emp_no
from salaries s
inner join dept_emp d on
s.emp_no=d.emp_no
inner join departments dd on
d.dept_no=dd.dept_no
group by 2,3;
My output is:
What should I modify from here?
For an employee, you seem to only want to include the department with the smallest salary. I would recommend using window functions:
select s.*
from (select s.*,
rank() over (partition by dept_name order by salary desc) as seqnum_d
from (select s.*, d.dept_name,
rank() over (partition by dept_name order by salary) as seqnum_ed
from salaries s join
dept_emp d
on s.emp_no = d.emp_no join
departments dd
d.dept_no = dd.dept_no
) s
where seqnum_ed = 1
) s
where seqnum_d = 1;
Something like this?
select m.salary, m.emp_no, salary.dept_name from salary,
(select emp_no, min(salary) salary from salary group by emp_no) m
where
m.emp_no=salary.emp_no and m.salary=salary.salary;

Need to find top 3 employees

I working with two tables
Employee ( empid integer, mgrid integer, deptid integer, salary integer)
Dept (deptid integer, deptname text)
I need to find top 3 employees (salary based), in every department. Result should have deptname, empid, salary sorted by deptname and then employee with high to low salary.
I appreciate all your help !!
There are two parts in this query. The inner and outer query.
First part, I am partitioning at deptid level and assigning the rank to the salaries in the descending order which solves your problem.
Second part is just a select on all the output fields by filtering out only the top three employees in each department.
Key point :- Assigning rank to the salaries for each department using ROW_NUMBER window function in the inner query solves the entire problem.
SELECT deptname,empid,salary
FROM
(
SELECT d.deptname,
e.empid,
e.salary,
ROW_NUMBER() OVER ( PARTITION BY e.deptid ORDER BY
e.salary DESC ) AS rank_salary_by_dept
FROM dept d, employee e
WHERE d.deptid = e.deptid
)
WHERE rank_salary_by_dept <= 3
ORDER BY deptname,rank_salary_by_dept;

Retrieve the names of employees who is making least in their departments

I have two tables
EMPLOYEE (Fname, Lname, Ssn, Salary, Dno)
DEPARTMENT (Dname, Dno, Location)
I want to list the names of all employees making the least in their department
I have come up with this
select min(E.Salary) from EMPLOYEE E group by E.Dno;
but how do I join the EMPLOYEE table with it and display the 'Fname' and 'Lname';
Analytic functions would be best but this would also work:
select *
from employee e
where salary = (select min(x.salary) from employee x where x.dno = e.dno)
Use Analytic function, ROW_NUMBER() OVER( PARTITION BY DNO ORDER BY SALARY) as RN. So, WHERE RN = 1 will give you the employee with least salary in each department.
Remember, if there are two employees with same salary, then you need to use DENSE_RANK to avoid similar rank.
Note : This answer is for Oracle.
A simple way to do it is to check that no one with a lower salary exists in the same department;
SELECT e1.*
FROM employee e1
WHERE NOT EXISTS(
SELECT 1 FROM employee e2 WHERE e1.dno = e2.dno AND e1.salary > e2.salary
);
An SQLfiddle to test with.