Sql numbers of employees by department - mysql

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

Related

Fetch only the department that has the highest number of employees

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)

find department with at least 2 employees

I need to make sql question which will show all departments with at least 2 people in it.
SELECT department.name
FROM department
INNER JOIN employee
ON department.id = employee.department_id
GROUP BY employee.id
HAVING COUNT(employee.id) >= 2;
It's not showing me anything with this query
I think you using GROUP BY on wrong column.
If you want to count employee in each department, then you need to GROUP BY department.id.
SELECT department.id, department.name, COUNT(employee.id) AS total_employee
FROM department
INNER JOIN employee
ON department.id = employee.department_id
GROUP BY department.id, department.name
HAVING COUNT(employee.id) >= 2;
Try this:
SELECT d.name
FROM department d
WHERE
(SELECT COUNT(*) FROM employee e
WHERE d.id = e.department_id) >= 2
In this way if you want to change your limit (instead of 2, another value) your query will work.
If you use INNER JOIN if you want, in the future all departments with no employees you can't use it.

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;

SQL count and group by not returning counts with 0

In my situation, I have an Employee table and a Department table. Most departments have employees, but there exist a few departments with zero employees.
I'm trying to pull up all departments, sorted with most employees to none.
I have tried both INNER JOIN and LEFT JOIN and still can't seem to get what I want.
SELECT COUNT(Department.DEPT_ID) as total, Department.Name
FROM Department
INNER JOIN Employee
ON Department.DEPT_ID = Employee.DEPT_ID
GROUP BY Department.Name
ORDER BY total desc, Department.NAME asc;
However, this excludes any departments with zero employees. I also tried:
SELECT Department.NAME, IFNULL(COUNT(Department.DEPT_ID), 0) as total
FROM Department
LEFT JOIN Employee
ON Employee.DEPT_ID = Department.DEPT_ID
GROUP BY Department.NAME
ORDER BY total desc, Department.NAME asc;
But this time, for any department with zero employees, it sets its value as 1, instead of 0 which is confusing me.
What am I doing wrong?
EDIT: Correct solution by #vkp is:
SELECT Department.NAME, IFNULL(COUNT(Employee.DEPT_ID), 0) as total
FROM Department
LEFT JOIN Employee
ON Employee.DEPT_ID = Department.DEPT_ID
GROUP BY Department.NAME
ORDER BY total desc, Department.NAME asc;
SELECT d.deptname,CASE WHEN e.total IS NULL THEN 0 ELSE e.total END AS total
FROM dept d
LEFT JOIN
(
SELECT deptid,COUNT(*) AS total
FROM emp
GROUP BY deptid
) e
ON d.deptid = e.deptid
ORDER BY CASE WHEN e.total IS NULL THEN 0 ELSE e.total END DESC;
SELECT Department.Name,
CASE
WHEN Employee.ID IS NULL THEN 0
ELSE COUNT(1)
END AS total
FROM Department
LEFT JOIN Employee
ON Department.DEPT_ID = Employee.DEPT_ID
GROUP BY Department.Name
ORDER BY total desc, Department.NAME asc;

sql, employee and department

Requirements: using one query only to show each department with their employee counts (two tables, department and employee); order by number of employees decreasing;(for departments with no employees, still show them); for departments with the same size, order by department name alphabetically. My solution not showing the departments with no employees, also, it is not showing alphabetically order of departments when same number of employees:
SELECT d.DEPT_ID,
DEPT_NAME, COUNT(s.STUDENT_ID) as numStudents
FROM Departments d, Students s
WHERE d.DEPT_ID = s.DEPT_ID
GROUP BY d.DEPT_ID
ORDER BY numStudents DESC;
Use a LEFT JOIN instead of the cross join you are currently doing.
SELECT d.DEPT_ID,
d.DEPT_NAME, COALESCE(COUNT(s.STUDENT_ID),0) as numStudents
FROM Departments d,
LEFT JOIN Students s
ON s.dept_id = d.dept_id
GROUP BY d.DEPT_ID, d.dept_name
ORDER BY numStudents DESC, DEPT_NAME;
In order to show departments with no students, you have to use LEFT JOIN, not a cross product. And to order by name when they have the same number of students, you need to add that to your ORDER BY clause.
SELECT d.DEPT_ID, DEPT_NAME, IFNULL(COUNT(s.STUDENT_ID), 0) AS numStudents
FROM Departments AS d
LEFT JOIN Students AS s ON d.DEPT_ID = s.DEPT_ID
GROUP BY d.DEPT_ID
ORDER BY numStudents DESC, DEPT_NAME