Inner Join: Is this an optimal solution? - sql

T1: employee [id, salary]
T2: department [name, employeeid]
(employeeid is a foreign key to T1's id)
Problem: Write a query to fetch the name of the department which receives the maximum salary.
My Solution:
SELECT DISTINCT name
FROM department AS a
INNER JOIN employee AS b ON a.employeeid = b.id
AND b.salary
IN (
SELECT max( salary )
FROM employee AS c
)
Edit: The problem statement is accurate, and we're not trying to find out the employee who has the highest salary. It says "....Department which receives.....", not "...employee who receives....".
Is this ok? Or can this be optimized?

GROUP BY the name of the department and order by SUM(salary).
SELECT department.name
FROM department
JOIN employee ON department.employeeid = employee.id
GROUP BY department.name
ORDER BY SUM(salary) DESC
LIMIT 1

How about:
SELECT employee.id, employee.salary, department.name
FROM department, employee
where
employee.id = department.employeeid and
employee.salary = (select max(salary) from employee)

Related

Join two table with department wise maximum salary

Department wise maximum salary in a table it's working:
select * from employee where (emp_dept, emp_sal)
in (select emp_dept, max(emp_sal) from employee group by emp_dept);
but my concern is : i want emp_id, emp_name, emp_sal, emp_dept column with department wise maximnum salary
customer table : cust_id, cust_name, emp_id
employee table : emp_id, emp_name, emp_sal, emp_dep
I think you want :
select e.emp_id, e.emp_name, e.emp_sal, e.emp_dept
from employee e
where e.emp_sal = (select max(e1.emp_sal) from employee e1 where e1.emp_dept = e.emp_dept);
Assuming you want all the records from the employee table with the maximum salary added, then you could use something like:
Select e.emp_id, e.emp_name, e.emp_sal, e.emp_dept, d.max_salary
from employee e
left join
(select emp_dept,max(emp_sal) as max_salary
from employee
group by emp_dept) d
ON e.emp_dept=d.emp_dept
The sub query calculates the maximum salary for each department and then using the left join you can get it into the final table.
If you want the employee details of the employee with the maximum salary, then:
Select e.emp_id, e.emp_name, e.emp_sal, e.emp_dept, d.max_salary
from employee e
inner join
(select emp_dept,max(emp_sal) as max_salary
from employee
group by emp_dept) d
ON e.emp_dept=d.emp_dept and e.emp_sal=d.max_salary
In this case the join is based on the salary component as well, thereby returning only the employees with the maximum salary. Hope this helps.
Just use a window function:
select e.*,
max(emp_sal) over (partition by emp_dept) as dept_max_sal
from employee ;

List the department name with the least number of employees

There are two tables, employee and dept:
How can I join the two tables and select the department with the least number of employees?
It would have been better to answer if you provided the table structure.
But give this a try:
SELECT deptname
FROM dept
WHERE deptid = (SELECT distinct deptid
FROM employee
ORDER BY COUNT(dept) limit 1);
Please try the following...
SELECT deptid,
deptname,
employeeCount
FROM
(
SELECT dept.deptid AS deptid,
dept.deptname,
COUNT( dept.deptid ) AS employeeCount
FROM dept
JOIN employee ON dept.deptid = employee.deptid
GROUP BY dept.deptid,
dept.deptname
)
GROUP BY deptid
HAVING employeeCount = MIN( employeeCount );
This statement starts with the inner query joining dept to employee on the shared field deptid. It then groups the resulting rows by department and returns to the outer query the department's id and name along with a count of employees for that department.
The outer query groups the data by department again, then selects the details of the department(s) having a count of employees equal to the minimum count of employees.
If you have any questions or comments, then please feel free to post a Comment accordingly.
I'm only answering because MIN isn't needed and LIMIT isn't Oracle:
select d.*
from (select deptid, count(*) as cnt
from employees e
group by deptid
order by count(*) asc
) d
where rownum = 1;
In Oracle 12C+, you don't need the subquery:
select deptid, count(*) as cnt
from employees e
group by deptid
order by count(*) asc
fetch first 1 row only;
Hi :) so my answer is a bit ugly, and full of nested queries. but I tested it and it worked for me...
-- First I created a couple of test tables and added a few records
drop table dept;
drop table employee;
create table dept (deptid number primary key, deptname varchar(20));
create table employee(employee_id number primary key, names varchar(20),
deptid number,foreign key (deptid) references dept(deptid));
insert into dept values(1,'HR');
insert into dept values(2,'Finance');
insert into dept values(3,'IT');
insert into employee values(1,'Tina',1);
insert into employee values(2,'Rob',1);
insert into employee values(3,'Lisa',1);
insert into employee values(4,'Will',2);
insert into employee values(5,'Lina',2);
insert into employee values(6,'Ethel',2);
insert into employee values(7,'Trevor',1);
insert into employee values(8,'Alanea',1);
insert into employee values(9,'Matthew',1);
insert into employee values(10,'Maddie',3);
insert into employee values(11,'Anna',1);
-- According to the added records, the answer we are looking for should be
the department name IT
-- select the department name from department table
select d.deptname from dept d,
/* This is where it gets ugly - basically, it counts the number of
employees in each department, then finds the id of the department that had
the smallest count */
(select deptid from
(select count(deptid) as counter, deptid from employee group by deptid)
where counter =( select min(counter)from
(select count(deptid) as counter, deptid from employee group by deptid))) minid
-- join the tables using deptid
where d.deptid = minid.deptid;
This query gave the correct answer for me even when I changed the records to make finance the correct answer.
If you have any questions give me a yell through the comments :)
select department_name, count(employee_id)
from department d
inner join employee e
on d.employee_id = e.employee_id
having count(employee_id) =
(
select min(count(employee_id)) /*This query returns minimum count*/
from department d
inner join employee e
on d.employee_id = e.employee_id
group by department_name
)
group by department_name;
WITH temp
AS
(SELECT e1.department_id, count(e1.employee_id) emp_count
FROM hr.employees e1
GROUP BY e1.department_id)
SELECT d1.department_name, t1.emp_count employee_count
FROM temp t1
,hr.departments d1
WHERE t1.department_id = d1.department_id(+)
AND NOT EXISTS
(SELECT 1
FROM temp t2
WHERE t2.emp_count < t1.emp_count)
ORDER BY 2,1 ;

How to get all departments with Employee number

I have an EmployeeDepartmetn juction table like this. I have all the departments in Depeartment table and employees in Employee table..
I want to get departments for an particular employee along with the all the departments available in depeartment table.
It should be like Select DepartmentId, DepartmentName, EmployeeID from Query.
Main criteria here is, Need to display NULL if the employee dont have that department. I am confused here...please help.
Please give Linq Query
Thanks in Advance
Put criteria in your left join:
Select distinct a.DeptID, b.DepartmentName, b.EmployeeID
From Department a
left join EmployeeDepartment b
on a.DeptID = b.DeptID and b.EmployeeID = 1 --insert employee ID here
It will show all departments (even those with no employees), then show the employee ID you chose in the third column only if that employee is assigned there.
You can do this with conditional aggregation:
select DeptId,
max(case when EmployeeId = 1 then EmployeeId end) as EmployeeId
from EmployeeDepartment ed
group by DeptId;
EDIT:
If you have a departments table as well:
select d.deptid, d.name, ed.employeeid
from Departments d left join
EmployeeDepartment ed
on d.deptid = ed.deptid and
ed.employeeid = 1;

Get MAX element based on two different tables

I have problem with SQL query on Oracle DB.. I have following tables:
DEPARTMENT(`ID` NUMBER(11), `NAME` VARCHAR(25))
EMPLOYEE(`ID` INT(11), `LASTNAME` VARCHAR(25), `DEP_ID` INT(11));
SALARIES(`ID` INT(11), `EMPLOYEE_ID` INT(11), `SALARY` INT(11));
Now, I want to get name of depratment with highest average sum of salary. Department isn't directly related to Salaries so probably I need to use Employee table as well.
I've created a query:
SELECT NAME, (SELECT SUM(SALARIES.SALARY) FROM SALARIES JOIN EMPLOYEE ON EMPLOYEE.EMPLOYEE_ID = EMPLOYEE.ID WHERE EMPLOYEE.DEP_ID = DEPARTMENT.ID GROUP BY EMPLOYEE.ID) AS AVG_OF_SUM FROM DEPARTMENT;
It returns list of department's name and avg sum. But now I need to get only one department name for the highest averange row.
Is my query actually OK? Or can be improved? And how can I get only one record?
Thanks for any help.
Regards,
D
Make use of the ANALYTIC function SUM...OVER
In the subquery, apply the analytic function, and then select only those rows which you desire.
For example,
SELECT DISTINCT DEPT, SUM(SAL) OVER (PARTITION BY DEPT ORDER_BY DEPT) SUM_SAL
FROM EMPLOYEE
ORDER_BY DEPT;
SELECT NAME, (SELECT MAX(SUM(SALARIES.SALARY))
FROM SALARIES
JOIN EMPLOYEE ON EMPLOYEE.EMPLOYEE_ID = EMPLOYEE.ID )
WHERE EMPLOYEE.DEP_ID = DEPARTMENT.ID
GROUP BY EMPLOYEE.ID) AS AVG_OF_SUM FROM DEPARTMENT;
SELECT NAME, avg_sal FROM
(SELECT d.NAME, avg(s.SALARY) avg_sal
FROM SALARIES s
JOIN EMPLOYEE e ON s.EMPLOYEE_ID = e.ID
JOIN DEPARTMENT d ON e.DEP_ID = d.ID
GROUP BY d.NAME
ORDER BY 2 DESC)
WHERE rownum = 1;
(This query shows a department with the highest avg salary. If you need sum replace AVG -> SUM)

SELECT specific information

My tables are structured like this (there are more values in the tables but I only wrote the ones relevant to this):
Department(dep_id, dep_name)
Employee(dep_id)
I need to display dep_name and the number of employees in every department, except once specific department (let's call it DepX) and only the departments with more than one employee.
I tried multiple methods to solve this but none of them worked.
Some methods I tried:
SELECT department.dep_name, COUNT(employee.dep_id) AS NumberOfEmployees FROM employee
INNER JOIN department ON employee.dep_id=department.dep_id
WHERE dep_name<>'DepX'
GROUP BY dep_id
HAVING COUNT(employee.dep_id) > 1;
SELECT dep_name FROM department
WHERE dep_name <>'DepX'
UNION
SELECT COUNT(*) FROM employee
WHERE COUNT(*) > 1
GROUP BY dep_id;
I can't figure this out. Thanks!
The first example does now work because you're including dep_name in your results without an aggregation but not grouping on it.
You can either use the department name in your grouping instead of the ID:
SELECT department.dep_name, COUNT(employee.dep_id) AS NumberOfEmployees FROM employee
INNER JOIN department ON employee.dep_id=department.dep_id
WHERE dep_name<>'DepX'
GROUP BY department.dep_name
HAVING COUNT(employee.dep_id) > 1;
or do the COUNT in a subquery:
SELECT department.dep_name,
e.NumberOfEmployees
FROM department
INNER JOIN (SELECT dep_id,
COUNT(*) NumberOfEmployees
FROM employee
GROUP BY dept_id
HAVING COUNT(dept_id) > 1
) e
ON department.dep_id = e.dep_id
WHERE dep_name<>'DepX'
SELECT department.dep_name, COUNT(employee.dep_id) AS NumberOfEmployees FROM employee
INNER JOIN department ON employee.dep_id=department.dep_id
WHERE department.dep_name not in('DepX')
GROUP BY department.dep_name
HAVING COUNT(employee.dep_id) > 1;
update your table alias per your need
TEST this. This query help you return not only dept_name, it can return all fields from Department if you want:
SELECT d.*, A.numOfEmployees
FROM Department d,
(
SELECT e.dep_id, COUNT(*) numOfEmployees
FROM Employee e
GROUP BY e.dep_id
HAVING COUNT(*) > 1
) A
WHERE d.dep_id = A.dep_id
AND d.dep_name != 'DepX'