join query in sql - mysql

Here is my SQL query and result. My requirement is to display department_name with a maximum staff count but I don't know how to do that.
I want a result like department_name - SE and staff_ count - 4 only.
select d.department_name, count(staff_id) from department d, staff sf
where d.department_id = sf.staff_id
group by department_name
order by count(staff_id) desc
DEPARTMENT_NAME COUNT(SF.STAFF_ID)
------------------------------ ------------------
SE 4
EEE 2
IT 2
CSE 2
ECE 1

You need to first get the count of each department and then select department with the maximum count. Therefore, you can use sub-query as following:
SELECT d_name, MAX (staff_cnt)
FROM (SELECT d.department_name as d_name, count(staff_id) as staff_cnt
FROM department d, staff sf
WHERE d.department_id = sf.staff_id
GROUP BY department_name);

Try this
alias query
select d.department_name, count(staff_id)
from department d, staff sf
where d.department_id = sf.staff_id AND d.department_name = 'SE'
group by department_name
order by count(staff_id) desc
JOIN Query
select d.department_name, count(staff_id)
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
WHERE d.department_name = 'SE'
group by department_name
order by count(staff_id) desc
LIMIT 1
OR Top
select TOP 1 d.department_name, count(staff_id)
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name
order by count(staff_id) desc

You should use LIMIT 1 for reduce the result but also use explicit join syntax for a better readability:
select d.department_name, count(staff_id)
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name
order by count(staff_id) desc
limit 1
Or without using limit you could try having on the max:
select d.department_name, count(staff_id) count_staff
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name
having count_staff = (
select max(count_staff)
from ( select d.department_name, count(staff_id) count_staff
from department d
INNER JOIN staff sf ON d.department_id = sf.staff_id
group by department_name ) t
)

Related

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.

Error Number: 1137 Can't reopen table: 'd'

select employee_id, first_name, last_name, department_name, location_id
from employees as e, departments as d
where d.department_id = e.department_id and (location_id)
in
(select location_id
from departments
where department_name = 'Finance')
It seems you don't need subquery to filter location_id
select employee_id, first_name, last_name, department_name, location_id
from employees as e join departments as d on d.department_id = e.department_id
where location_id in (select location_id from departments where department_name = 'Finance')
Note: it's better to use explicit join instead of comma separated join
You could use an inner join instead of an IN clause
select employee_id
, first_name
, last_name
, department_name
, d.location_id
from employees as e
INNER JOIN departments as d ON d.department_id = e.department_id
INNER JOIN ( select location_id
from departments
where department_name = 'Finance') t ON t.location_id = d.location_id
And for readability you should us explicit JOIN syntax, and not implicit syntax based on WHERE.

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;

Selecting employees from database where the company contains between 1 and 5 employees

So far I have this query:
SELECT
c.id AS company_id,
c.company_name,
COUNT(*) AS employee_count
FROM
ct_companies c
INNER JOIN ct_employees e ON c.id = e.company_id
GROUP BY
c.domain,
c.postcode,
c.company_name
HAVING
(
employee_count >= 1
AND employee_count <= 5
)
ORDER BY
employee_count DESC
Now, this works great, it selects companies who have at least 1 employee but no more than 5 and shows me the employee count.
But what I want to be able to do, is select every employee within a company, but only where that company has between 1 and 5 employees like above.
So something like
SELECT e.id FROM ct_employees e WHERE (employee_count >= 1 AND employee_count <= 5)
You could try
SELECT e.id,
d.employee_count
FROM ct_employees e
INNER JOIN (SELECT c.id AS company_id,
COUNT(*) AS employee_count
FROM ct_companies c
INNER JOIN ct_employees e1
ON c.id = e1.company_id
GROUP BY c.domain,
c.postcode,
c.id
HAVING COUNT(*) >= 1
AND COUNT(*) <= 5) d
ON d.company_id = e.company_id
ORDER BY employee_count DESC

SQL aggregation group by

I have an employee table and a leave_allocation table which has a one-to-many relationship, Each employee has a number of leave allocations over a period of time. I would like to get the LATEST allocation for each employee.
I tried the query but the date and the days values do not correlate to the same row
select e.employee_number, e.nme, MAX(l.date), l.days
from employee e, leave_allocation l
where l.employee_id = e.employee_id
group by e.employee_number, e.nme
How can I get the latest allocation per employee?
SELECT e.employee_number
,e.nme
,l.days
FROM employee e
, leave_allocation l
,(SELECT employee_id
,MAX(DATE) date
FROM leave_allocation
GROUP BY employee_id) m
WHERE l.employee_id = e.employee_id
AND l.employee_id = m.employee_id
AND l.date = m.date
If there can be multiple rows with same employee_number and date, then you need to sum.
SELECT e.employee_number
,e.nme
,sum(l.days)
FROM employee e
, leave_allocation l
,(SELECT employee_id
,MAX(DATE) date
FROM leave_allocation
GROUP BY employee_id) m
WHERE l.employee_id = e.employee_id
AND l.employee_id = m.employee_id
AND l.date = m.date
GROUP BY e.employee_number
,e.nme
Place the MAX() date in a subquery:
SELECT e.employee_number, e.nme, l.leavedate, la.days
FROM employee e
INNER JOIN
(
SELECT Max(date) leavedate, employee_id
FROM leave_allocation
GROUP BY employee_id
) l
ON e.employee_id = l.employee_id
INNER JOIN leave_allocation la
ON l.employee_id = la.employee_id
AND l.leavedate = la.date
I also switched the query to use ANSI join syntax instead of commas between the tables.
Try this one,
SELECT e.employee_number, e.nme, c.maxDate, l.days
FROM employee e
INNER JOIN leave_allocation l
ON l.employee_id = e.employee_id
INNER JOIN
(
select employee_id, MAX(date) maxDate
from leave_allocation
group by employee_id
) c ON c.employee_id = l.employee_ID AND
c.maxDate = l.date