SQL Multiple inner joins - mysql

I am working on a sql query to do the following:
For each project, retrieve the project number, the project name, and the number of employees from department 5 who work on the project.
So far my query looks like this:
SELECT p.PNO
, p.PNAME
, COUNT( DISTINCT w.ESSN) '# employees from Dept. 5'
FROM project p
JOIN department d
ON d.DNO = p.DNO
JOIN employee e
ON e.DNO = d.DNO
JOIN works_on w
ON w.ESSN = e.SSN
WHERE e.DNO LIKE '5'
AND p.PNO LIKE 10
Where I am testing it for project number 10 which should return the number of employees from Dept. 5 as 1, however it returns NULL. I think that I need to somehow join the project and employee tables but I am unsure
Attached is my schema
ER Diagram

Your joins are wrong.
You should be joining only projects, works_on and employee tables.
SELECT p.PNO, p.PNAME, COUNT( DISTINCT w.ESSN) '# employees from Dept. 5'
FROM project p
INNER JOIN works_on w
ON p.pno = w.pno
INNER JOIN employee e
ON w.essn = e.essn
WHERE e.DNO LIKE '5' AND p.PNO LIKE 10
And you are missing the group by at the end:
GROUP BY p.PNO, p.PNAME

Related

Issue with select statements in MySQL past exam paper

Im going over a past paper and have found some select statements I cannot do. Can anyone help with these? I'm using MySQL. Thanks
Schema:
employee = (employee id, name, address, date of birth, salary)
project = (project id, name, budget, start date, end date)
manages = (employee id, project id)
works on = (employee id, project id)
Questions :
Names and addresses of all employees who work on projects which are
current (have not ended yet)
The names of managers of projects, ordered by the total number of employees they manage
The names of employees who work on the project with the largest budget
amount.
My attempts:
1.
select employee.name, address
from employee natural join works_on natural join project
where end_date is null
2.
select employee.name, count(works_on.employee_id) as manages_count
from (employee natural join manages) joins works_on using (employee_id)
I'm completely lost I cannot even attempt this one ^
3.
select employee.name, address, budget
from employee natural join works_on natural join project
order by budget
limit n
^ I know this is wrong as technically I should be able to show them without a limit
Here you go:
1.
select
e.name,
e.address
from employee e
join works_on w on w.employee_id = r.employee_id
join project p on p.project_id = e.project_id
where p.end_date is null
2.
select
n.name
from employee n
join manages m on m.employee_id = n.employee_id
join works_on w on e.project_id = m.project_id
group by n.employee_id
order by count(*) desc
3.
select
e.name
from employee e
join works_on w on w.employee_id = e.employee_id
join project p on p.project_id = w.employee_id
where p.project_id in (
select project_id from project where budget = (
select max(budget) from project
)
)

Comparing two SQL queries when using IN

I have two tables, for example the Employee and Project tables:
Employee (id, dept, joining_date)
Project (emp_id, project)
With Project having foreign key from Employee table.
I have to query on project and dept and return Employee in the order of their joining_date. Which query will work faster on big data set on the queries below?
select * from Employee where id in (select p.emp_id from Project p join Employee e on p.emp_id = e.id where p.project = 'project1' and e.dept = 'dept1') order by joining_date
select * from Employee where id in (select p.emp_id from Project p join Employee e on p.emp_id = e.id where p.project = 'project1' and e.dept = 'dept1') and dept = 'dept1' order by joining_date
Or is there any better and simpler way to do so?
The outer query using the IN() expression serves no purpose is entirely unnecessary. This will produce the output you need:
select e.*
from Project p
inner join Employee e on p.emp_id = e.id
where p.project = 'project1' and e.dept = 'dept1'
order by joining_date

MySQL - Arithmetic operations with relations

How do I get the amount of income each employee automatically, based on how the number of employees who participated in the construction project .
Already tried this , but the error . Subquery returned more than 1 row .
SELECT e.name,
( SELECT( p.costs / count(r.employee_id))
FROM relation_employee r GROUP BY r.project_id ) AS revenue
FROM project p
INNER JOIN relation_employee r ON p.id = r.project_id
INNER JOIN employee e ON r.employee_id = e.id
table employee
id INT
name VARCHAR
table project
id INT
name VARCHAR
costs INT
table relation_employee
employee_id INT
project_id INT
Instead of using a correlated subquery in the select part you could get the employee count per project as a derived table to use in the from part, which at least to me looks a bit cleaner. The query could look like this:
-- revenue per employee
SELECT e.name, sum(p.costs * 1.0 / emp_count) AS revenue
FROM project p
INNER JOIN relation_employee r ON p.id = r.project_id
INNER JOIN (SELECT project_id, count(employee_id) emp_count FROM relation_employee GROUP BY project_id) c ON c.project_id = p.id
INNER JOIN employee e ON r.employee_id = e.id
GROUP BY e.name;
-- revenue per employee and project
SELECT
e.name as employee_name,
p.name as project_name,
sum(p.costs / emp_count) AS revenue
FROM project p
INNER JOIN relation_employee r ON p.id = r.project_id
INNER JOIN (SELECT project_id, count(employee_id) emp_count FROM relation_employee GROUP BY project_id) c ON c.project_id = p.id
INNER JOIN employee e ON r.employee_id = e.id
GROUP BY e.name, p.name;
Sample SQL Fiddle

MySQL Query - earn over the average salary

I am trying to get this query to work. Basically it is getting all people that earn't a degree at Oxford Brookes that now earn a salary over the average salary of the whole database.
I have searched for hours trying to find a solution. Please feel free to offer advice, so that I may learn from this and solve my issue. Thanks
SELECT a.personid,
a.firstname,
a.lastname,
b.placeofstudy,
AVG(c.salary)
FROM person a
INNER JOIN award d
ON a.personid = d.personid
INNER JOIN qualification b
ON d.qualid = b.qualid
INNER JOIN job c
ON a.personid = c.personid
WHERE placeofstudy = 'Oxford Brookes'
GROUP BY a.personid;
This currently produces no errors but does not return the average salary, just each persons current salary.Even when I add 'having c.salary > avg(c.salary)' it refuses to work.
select a.personid, a.firstname, a.lastname, b.placeofstudy, c.salary, (select avg(salary) from job) as AvgSalary
from person a
inner join award d on a.personid = d.personid
inner join qualification b on d.qualid = b.qualid
inner join job c on a.personid = c.personid
where placeofstudy = 'Oxford Brookes'
and c.salary > (select avg(salary) from job)
You need to use the keyword HAVING.
Try this:
select a.personid, a.firstname, a.lastname, b.placeofstudy, avg(c.salary) AS avgsalary
from person a
inner join award d
on a.personid=d.personid
inner join qualification b
on d.qualid=b.qualid
inner join job c
on a.personid=c.personid
where placeofstudy = 'Oxford Brookes'
group by a.personid, a.firstname, a.lastname, b.placeofstudy
having c.salary > avgsalary

Count the number of employees for supervisor

SELECT
e.lname AS employee_name
, s.lname AS supervisor_name
, e.superssn AS supervisor_ssn
FROM employee e INNER JOIN employee s
WHERE e.superssn=s.ssn
I actually have two questions. The first one is, the above statement works just fine. However right now it will show bunch of employees with their supervisor. Not well organized. By the way there are three supervisors. Is there a way to show let's say supervisor A with employees A and supervisor B with employees B and so on?
The second problem is that I also tried to just count the number of employees for each supervisor rather than showing their name with COUNT(), I tried several different ones but non worked.
A few things
1) It is good practice to keep your join predicate with your join. So change:
FROM employee e INNER JOIN employee s WHERE e.superssn = s.ssn
To:
FROM employee e INNER JOIN employee s ON e.superssn = s.ssn
2) To keep them together by supervisor, just use an order by:
SELECT
e.lname AS employee_name
, s.lname AS supervisor_name
, e.superssn AS supervisor_ssn
FROM employee e INNER JOIN employee s ON e.superssn = s.ssn
ORDER BY s.lname
3) To do a count of employees for each supervisor use a group by and the COUNT aggregate function
SELECT
s.lname AS supervisor_name,
COUNT(*) AS employee_count
FROM employee e INNER JOIN employee s ON e.superssn = s.ssn
GROUP BY s.lname
ORDER BY s.lname