sql, employee and department - mysql

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

Related

Retrieving data from three different columns

I have three different tables salaries, dept_managers(Department managers), and departments
the first two tables are connected through emp_no(Employee number), While the other two tables are connected through dept_no(the department number),
I want to have a query that gives me the average amount of salaries that each department has.
I tried this query but It did not work.
SELECTd.dept_name,dm.dept_noFROM departments d
JOIN dept_manager dm ON dm.dept_no = d.dept_no
JOIN(
SELECT AVG(salary) AS Average_salary
FROM salaries s
GROUP BY salary)
ON d.emp_no = dm.emp_no
;
maybe I'm missing something here but wouldn't you just join department to employees and then join salaries to employees and get the avg salary grouped by department?
select d.dept_name, avg(s.salary)
from departments d join employees e on (e.dept_no = d.dept_no)
join salaries s on (s.emp_no = e.emp_no)
group by d.dept_name

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

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;

Find employee with lowest salary but also his department

I need to find employee with lowest salary- first and last name, gender and department.
I tried with this but I have problems adding department name.
SELECT first_name, last_name, gender, salary FROM salaries
JOIN employees using(emp_no) where order by salary desc limit 0,1;
Any help?
schema-link
This should work, you are missing a couple of joins among other things (like the department name in the field list):
SELECT e.first_name, e.last_name, e.gender, s.salary, d.dept_name
FROM salaries AS s
INNER JOIN employees AS e ON s.emp_no=e.emp_no
INNER JOIN dept_emp AS de ON de.emp_no=e.emp_no
INNER JOIN departments AS d ON d.dept_no=de.dept_no
ORDER BY s.salary ASC limit 0, 1