Fetch only the department that has the highest number of employees - mysql

I have 2 tables in my database.
Table 1. employee
id
name
department_id
Table 2. department
id
name
What will be the query to fetch all employees with their department?
So I have written this query
SELECT employee.name
, department.name
FROM employee
JOIN department
ON employee.department_id = department.id
And this seems to be correct but I am not able to write a query if I want to fetch only the department that has the highest number of employees. How can I achieve this?

To guarantee just one department...
SELECT
*
FROM
department
WHERE
id = (SELECT department_id
FROM employee
GROUP BY department_id
ORDER BY COUNT(*) DESC
LIMIT 1
)
Note, if two departments are tied with joint maximum employees, this will still only select One of them (arbitrarily chosen, potentially different each time).
To handle ties, you could do the following...
SELECT *
FROM department
WHERE id IN (SELECT department_id
FROM employee
GROUP BY department_id
HAVING COUNT(*) = (SELECT COUNT(*)
FROM employee
GROUP BY department_id
ORDER BY COUNT(*) DESC
LIMIT 1
)
)

This is a real pain to handle in MySQL. Here is one option:
SELECT d1.id, d1.name
FROM department d1
INNER JOIN employee e1
ON d1.id = e1.department_id
GROUP BY d1.id, d1.name
HAVING COUNT(*) = (SELECT COUNT(*) FROM department d2 INNER JOIN employee e2
ON d2.id = e2.department_id
GROUP BY d2.id ORDER BY COUNT(*) DESC LIMIT 1);
Note that if you were using a database with analytic function support, such as SQL Server, then the problem gets much easier:
SELECT id, name
FROM
(
SELECT d.id, d.name, DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) dr
FROM department d
INNER JOIN employee e
ON d.id = e.department_id
GROUP BY d.id, d.name
) t
WHERE t.dr = 1;

This question can be solved in multiple ways:
Using sub query
SELECT name FROM department
WHERE id IN
(SELECT department_id FROM employee HAVING COUNT(department_id)
IN
(SELECT MAX(COUNT(department_id)) FROM employee) GROUP BY department_id)
Using Join
SELECT name FROM employee e
INNER JOIN
department d ON e.department_id = d.id
HAVING COUNT(e.department_id)
IN
(SELECT MAX(COUNT(department_id)) from employee) group by department_id)

first check the column related two types have same name, same data type and the use subquery
SELECT name
FROM department
WHERE id IN (
SELECT department_id
FROM employees
HAVING COUNT(department_id) IN (
SELECT MAX(COUNT(dept_id))
FROM employees
)
GROUP BY department_id
)

Your query should work for the first question.
for the second, You can use this. The sub query would give you the dept Id for the most employees, which the outer query would give additional details for.
select * from department where department_id in
(select limit 1 Employee.department_id from Employee group by department_id
order by count(Employee.name) desc)

Related

SELECT MAX(COUNT) MySQL

I am new to MySQL, and I have a task to do right now where I have three tables:
students(id,name)
courses(id,name)
grades(id, student_id (FK), course_id(FK), grade)
I am supposed to
fetch the name of the course that is the most registered by students and if there is any conflict or ties with other course, retrieve the course after sorting ascendingly.
I tried several queries, but they are not 'efficient enough'
SELECT course.name FROM (
SELECT CI ,MAX(Total) FROM
(
SELECT course_id as CI,COUNT(*) AS Total
FROM grades
GROUP BY course_id ASC
) AS Results
) AS x
INNER JOIN courses ON x.CI = courses.id
And
SELECT courses.name FROM (
SELECT course_id, COUNT(*) AS how_many
FROM grades
GROUP BY course_id ASC
HAVING how_many = (
SELECT COUNT(*) AS how_many
FROM grades
GROUP BY course_id
ORDER BY how_many DESC
LIMIT 1
)
LIMIT 1
) AS X
JOIN courses ON X.course_id=courses.id
Is there any more efficient query?
Both your query attempts look logically incorrect to me. You should be joining courses to grades to obtain the number of students enrolled in each course. Regarding efficiency, the RANK analytic function is one of the most performant options, assuming you are running MySQL 8+:
WITH cte AS (
SELECT c.id, c.name, RANK() OVER (ORDER BY COUNT(*) DESC, c.name) rnk
FROM courses c
INNER JOIN grades g ON g.course_id = c.id
GROUP BY c.id, c.name
)
SELECT id, name
FROM cte
WHERE rnk = 1;
On earlier versions of MySQL, we can use a LIMIT query:
SELECT c.id, c.name
FROM courses c
INNER JOIN grades g ON g.course_id = c.id
GROUP BY c.id, c.name
ORDER BY COUNT(*) DESC, c.name
LIMIT 1;
You can use the ORDER BY clause with the LIMIT clause to get what you need, without aggregating twice:
WITH enrollments AS (
SELECT course_id, COUNT(DISTINCT student_id) AS num_enrollments
FROM grades
GROUP BY course_id
)
SELECT *
FROM enrollments e
INNER JOIN courses c
ON e.course_id = c.id
ORDER BY e.num_enrollments DESC, c.name ASC
LIMIT 1
The subquery will get you the enrollments by aggregating on the students,
then it is joined with the courses to use the course name.
Data is then ordered by:
number of enrollments descendent
course name ascendent
and only the first row is considered.

Find the salary of the youngest and eldest employee in each department

There are two tables
1) Employee
id | Name | Department | Dob
2) Salary
id | salary
I want to find the salary of the youngest and eldest employee in each department.
But using the the following query i am not able to get the correct id,salary.
SELECT salary.id,employee.Dept,salary.salary,MIN(employee.DoB)
from employee
INNER JOIN salary ON salary.id = employee.id GROUP by Dept
The above query is returning correct Dob but the ids and the salary are not matching with the Date of birth.
If you are running MySQL 8.0, just use window functions:
select *
from (
select
e.*,
s.salary,
row_number() over(partition by department order by dob asc) rn_asc,
row_number() over(partition by department order by dob desc) rn_desc
from employee e
inner join salary s on s.id = employee.id
) t
where 1 in (rn_asc, rn_desc)
In earlier versions, one option is to join with an aggregate query:
select e.*, s.salary
from employee e
inner join salary s on s.id = employee.id
inner join (
select department, min(dob) min_dob, max(dob) max_dob
from employee
group by department
) d on d.department = e.department and e.dob in (d.min_dob, d.max_dob)
I think I would use = twice with correlated subqueries:
select s.*, e.department
from salary join
employee e
on s.id = e.id
where e.dob = (select min(e2.dob) from employee e where e2.department = e.department) or
e.dob = (select max(e2.dob) from employee e where e2.department = e.department) ;
With an index on employee(department, dob), I would expect this to have very good performance.

Sql numbers of employees by department

I have 2 tables employees(id, first_name, last_name, salary, department_id_ and department(id, name) and I want to show number of employees in each department.
I have this question here:
SELECT department.name, COUNT(*) AS 'employees_number'
FROM department
LEFT JOIN employees
ON employees.department_id = department.id
GROUP BY department.id, department.name;
But for some reason, in departments where I have no people, it shows a number of employees as 1. Any idea why this is happening?
With an outer join you still get a result row when no match in the outer table is found. Only all employee column values are null then.
So rather than count the records, you want to count matched records, i.e. where an employee was found and its data is not null. So Count a column in the employee table (nulls are not counted, when counting a column or expression). E.g. use COUNT(e.department_id) or COUNT(e.id):
SELECT d.name, COUNT(e.id) AS employees_number
FROM department d
LEFT JOIN employees e ON e.department_id = d.id
GROUP BY d.id, d.name;
What I prefer though, is to aggregate/count before joining. The query looks a bit more complicated, but is less prone to errors on future query changes:
SELECT d.name, COALESCE(e.how_many, 0) AS employees_number
FROM department d
LEFT JOIN
(
SELECT department_id, COUNT(*) AS how_many
FROM employees
GROUP BY department_id
) e ON e.department_id = d.id;
As it's one aggregated column only you want, you can move the subquery to your SELECT clause and get thus a simpler query:
SELECT
d.name,
(
SELECT COUNT(*)
FROM employees e
WHERE e.department_id = d.id
) AS employees_number
FROM department d;
Using SUM instead of COUNT also can give you what you want:
SELECT
department.name,
SUM(CASE WHEN employees.id IS NOT NULL THEN 1 ELSE 0 END) AS 'employees_number'
FROM department
LEFT JOIN employees
ON employees.department_id = department.id
GROUP BY department.id, department.name;
SQL Fiddle:
http://sqlfiddle.com/#!9/8b8976/1
select department.name, count(employee.id) as co from
department left join employee on
department.id = employee.dept_id group by department.name
order by co desc, department.name asc

how to display the name of the departments that has the least student count

how to write a query to display the name of the departments that have the least student count. Sort the result based on department name in ascending order
select d.department_name from
(select dd.department_name, count(di.department_id) as id from student di
join department dd on di.department_id=dd.department_id group by dd.department_name) d,
(select min(count(*)) as new from student group by department_id) d2
where d.id=d2.new;
select d.department_name from Department d, Student s where
d.department_id = s.department_id
group by d.department_name
having count(s.student_id)<=all
(select count(s.student_id) from Department d, Student s where
d.department_id = s.department_id
group by d.department_name)
order by department_name;
Try this.
select d.department_id, d.department_name
from Department d
join Student s on d.department_id = s.department_id
group by d.department_id
having count(s.student_id) = (select min(count(s2.student_id))
from student s2
join department d2
on s2.department_id = d2.department_id
group by d2.department_id)
order by d.department_name
You must join the 2 tables to have the needed information.
You'll also have to group them by the selected information such that you can count the students.
And lastly, you place the condition. Needing a subquery to retrieve the minimum number of students.
select department_name
from Department
join Student
on Department.department_id=Student.department_id
having count(*) in
( select min(count(*)) from Student group by department_id)
group by Department.department_id,department_name
order by department_name asc;

select department(s) with maximum number of employees

I have two tables EMP(id,name,DEPT_id) and DEPT(id ,name). I need to find the department(s) in which the maximum number of employees work. Please help.
This will give the department name of the department which is having maximum number of employees.
Select DEPT_NAME from department where DEPT_ID = (select DEPT_ID from (Select DEPT_ID, count(DEPT_ID) from Employee group by DEPT_ID order by count(DEPT_ID) desc) where rownum = 1);
Just a little more verbose than the other two solutions, but it will get the job done...feel free to tweak to your convenience.
select countbydept.*
from
(
-- from EMP table, let's count number of records per dept
-- and then sort it by count (highest to lowest)
-- and take just the first value. We just care about the highest
-- count
select dept_id, count(*) as counter
from emp
group by dept_id
order by counter desc
limit 1
) as maxcount
inner join
(
-- let's repeat the exercise, but this time let's join
-- EMP and DEPT tables to get a full list of dept and
-- employe count
select
dept.id,
dept.`name`,
count(*) as numberofemployees
from dept
inner join emp on emp.dept_id = dept.id
group by dept.id, dept.`name`
) countbydept
-- combine the two queries's results by matching the employee count
on countbydept.numberofemployees = maxcount.counter
Example: http://sqlfiddle.com/#!9/7d6a2d/1
Try this query.
SELECT a.name,Max(a.NumEmp) AS maxEmpCount FROM ( SELECT d.name,COUNT(*) AS NumEmp FROM EMP e INNER JOIN DEPT d ON e.DEPT_id = d.id GROUP BY e.DEPT_id ) AS a GROUP BY a.name
you can solve this using with statement like this:
with deps as
(select dep.department_name as dep_name, count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
group by dep.department_name)
select deps.dep_name,cnt from deps
where cnt=(select max(cnt) from deps)
OR
select dep.department_name as dep_name, count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
group by dep.department_name
having count(emp.employee_id) >= all (select count(emp.employee_id) as cnt
from departments dep
inner join employees emp
on emp.department_id =
dep.department_id
group by dep.department_name)
OR
with s1 as
(select dep.department_name as dep_name,
count(emp.employee_id) over(partition by dep.department_name) as cnt
from departments dep
inner join employees emp
on emp.department_id = dep.department_id
order by cnt desc),
s2 as
(select s1.dep_name,
s1.cnt,
row_number() over(order by cnt desc) as row_num
from s1)
select dep_name from s2 where row_num = 1
these solutions are proper for databases like Oracle that we do not have top(1) or limit 1
select Top 1 d.DNAME,count(e.ename) as counts from emp e,dept d where d.DEPTNO=e.DEPTNO
group by d.DNAME
order by counts desc
Or
select d.DNAME,count(e.ename) as counts from emp e,dept d where d.DEPTNO=e.DEPTNO
group by d.DNAME
having count(e.ename) = (select max(micount) from (select count(deptno) micount from emp group by DEPTNO) a)
You can try this query.
Select Id, Name from Dept
Where Id = (Select Top(1) DeptId from Emp
Group By DeptId
order by Count(DeptId) desc)
you can create view to find it.
CREATE VIEW TEMP AS SELECT COUNT(EMP.id) AS A, DEPT.name AS B
FROM EMP JOIN DEPT ON EMP.DEPT_id=DEPT.id GROUP BY DEPT.id;
SELECT MAX(A) FROM TEMP;
Now, EMP(id,name,DEPT_id) and DEPT(id ,name) these two tables are given. Now, I insert some entries in the table in such a manner that:
SELECT COUNT(*) AS NO_OF_EMPLOYEES,
DEPARTMENT.DEPT_NAME
FROM EMP, DEPARTMENT
WHERE EMP.DEPT_ID=DEPARTMENT.DEPT_ID
GROUP BY EMP.DEPT_ID
ORDER BY NO_OF_EMPLOYEES;
This query generates the following:
NO_OF_EMPLOYEES DEPT_NAME
3 Research
3 Finance
4 Sales
4 Product
Now, the query which gives the correct result:
SELECT COUNT(*) AS MAX_NO_OF_EMPLOYEES,
DEPARTMENT.DEPT_NAME
FROM EMP, DEPARTMENT
WHERE EMP.DEPT_ID=DEPARTMENT.DEPT_ID
GROUP BY EMP.DEPT_ID
HAVING MAX_NO_OF_EMPLOYEES=(
SELECT COUNT(*) AS NO_OF_EMPLOYEES
FROM EMP
GROUP BY DEPT_ID
ORDER BY NO_OF_EMPLOYEES DESC
LIMIT 1
);
It will generate:
MAX_NO_OF_EMPLOYEES DEPT_NAME
4 Sales
4 Product
This question can be solved in multiple ways
Using sub query
SELECT name FROM dept WHERE id IN (SELECT dept_id FROM emp HAVING COUNT(dept_id) IN (SELECT MAX(COUNT(dept_id)) FROM emp) GROUP BY dept_id)
Using Join
SELECT name FROM emp e INNER JOIN dept d ON e. dept_id = d. id HAVING COUNT(e.dept_id) IN (SELECT MAX(COUNT(dept_id)) from emp) group by dept_id)
If you have only emp table then below query will hep you get a results -
select a.* from (select deptno, dense_rank() over(order by count(*) desc ) as rank from dbo.emp group by deptno) a where a.rank =1
select deptno,count(*)from emp group by
deptno having count(*)=(select max(count(*))from emp group by deptno);
SELECT department_id, count(employee_id) as 'No_of_Emp'
FROM employees
GROUP BY department_id
ORDER BY No_of_Emp DESC