How to inner join 3 tables? - mysql

I'm having trouble with creating a view using the Inner Join, i have these 3 tables
Projects (ProjID, ProjName, InitDate, EndDate)
Employees (EmpID, EmpName, Phone, City, Salary)
Assign (ProjID, EmpID, Hours, Status, Date)
What i am triying to do is to create a view with the name "View1" to show me these information:
(ProjID / ProjName / EmpName / Hours) only with the employees who has
a Project ID (ProjID) that begins with "N".
I used this query:
CREATE OR REPLACE VIEW view1 AS
SELECT
projects.ProjID,
projects.ProjName,
employees.EmpName,
assign.Hours
FROM
assign
INNER JOIN employees ON employees.EmpID = assign.EmpID
INNER JOIN projects
WHERE
projects.ProjID LIKE "N%";
The result i got is not working and it shows multiple times the same employee with different Projects ID

you could use this query
select *
from employees
inner join assign on employees.EmpID=assign.EmpID
inner join projects on projects.ProjID=assign.ProjID
where projects.ProjID LIKE "N%";
the difference with your query is that you need to establish the relation between projects and assignments.
Anyway if you have the same employee assigned to more than one project that match the where clause, you will get that employee more than once.
Maybe you should group and use some aggregation formula like sum(hours)

CREATE OR REPLACE VIEW v1 AS
(
SELECT p.ProjID, p.ProjName, e.EmpName, a.Hours
FROM Projects p
INNER JOIN Assign a ON a.ProjID=p.ProjID
INNER JOIN Emplyees e ON e.EmpID = a.EmpID
WHERE p.ProjID LIKE "N%";
);
I would like to remind that if you will SUM(a.Hours)
you will have to group the other projections.

Related

Having trouble a query and specifically with joins

The code below is completely wrong and does not work at all. Im basically trying to look through my tables and compile a list of DeptName and the total student number for a department where a department has more than 40 students.
Im confused about joins in general and if someone could explain and show where im going wrong. im sure there is also other problems so any help with them would help
So basically one department is connected to one module, and a student is enrolled in a module. A student cannot take a module outside of their department. So each student should have one module that connects to one department
All of the ID fields in other tables are foreign keys as you can guess and changing the tables is not what I want to do here I just want to do this query as this stands
Relevant tables columns
Table Department DeptID, DeptName, Faculty, Address
Table Modules ModuleID, ModuleName, DeptID, Programme
Table Students StudentID,StudentName,DoB,Address,StudyType,`
Table Enrolments EID,StudentID,ModuleID,Semester,Year
SELECT Department.DeptName, COUNT(Student.StudentID) AS 'No of Students' FROM Department LEFT JOIN Module ON Department.DeptID= Module.DeptID LEFT JOIN Enrolment ON Module.ModuleID= Enrolment.StudentID LEFT JOIN Student.StudentID
GROUP BY(Department.DeptID)
HAVING COUNT(Student.StudentID)>=40
I have not included every table here as there are quite a lot.
But unless i've got this completely wrong you don't need to access a ModuleID in a staff table for the module they teach or something not relevant to this at all. As no student or Dept details are in there.
If that is the case i will fix it very quickly.
SELECT Department.DeptName, COUNT(Student.StudentID) AS 'No of Students'
FROM Department
LEFT JOIN Module
ON Department.DeptID= Module.DeptID
LEFT JOIN Enrolment
-- problem #1:
ON Module.ModuleID= Enrolment.StudentID
-- problem #2:
LEFT JOIN Student.StudentID
-- problem #3:
GROUP BY(Department.DeptID)
HAVING COUNT(Student.StudentID)>=40
You're joining these two tables using the wrong field. Generally when the modeling is done correctly, you should use USING instead of ON for joins
The right side of any JOIN operator has to be a table, not a column.
You have to group by every column in the select clause that is not part of an aggregate function like COUNT. I recommend that you select the DeptID instead of the name, then use the result of this query to look up the name in a subsequent select.
Note : Following code is untested.
WITH bigDepts AS (
SELECT DeptId, COUNT(StudentID) AS StudentCount
FROM Department
JOIN Module
USING ( DeptID )
JOIN Enrolment
USING ( ModuleID )
JOIN Student
USING ( StudentID )
GROUP BY DeptID
HAVING COUNT(StudentID)>=40
)
SELECT DeptID, DeptName, StudentCount
FROM Department
JOIN bigDepts
USING ( DeptID )
Instead of left join you need to use inner join since you need to select related rows only from those three tables.
Groupy by and having clause seems fine. Since you need departments with more than 40 students instead of >= please use COUNT(e.StudentID)>40
SELECT d.DeptName, COUNT(e.StudentID) AS 'No of Students' FROM Department d INNER JOIN Module m ON d.DeptID= m.DeptID inner JOIN Enrolment e ON m.ModuleID= e.StudentID LEFT JOIN Student.StudentID
GROUP BY(d.DeptName)
HAVING COUNT(e.StudentID)>40
So your join clause was a bit iffy to students as you wrote it, and presumably these should all be inner joins.
I've reformatted your query using aliases to make it easier to read.
Since you're counting the number of rows per DeptName you can simply do count(*), likewise in your having you are after counts greater than 40 only. Without seeing your schemas and data it's not possible to know if you might have duplicate Students, if that's the case and you want distinct students count can amend to count(distinct s.studentId)
select d.DeptName, Count(*) as 'No of Students'
from Department d
join Module m on m.DeptId=d.DeptId
join Enrolment e on e.StudentId=m.ModuleId
join Students s on s.StudentId=e.studentId
group by(d.DeptName)
having Count(*)>40
Also, looking at your join conditions, is the Enrolement table relevant?
select d.DeptName, Count(*) as 'No of Students'
from Department d
join Module m on m.DeptId=d.DeptId
join Students s on s.StudentId=m.moduleId
group by(d.DeptName)
having Count(*)>40

Two table joins for one query -- confusing result

I'm trying to execute two separate inner table joins in my query to return values from two tables.
SELECT pname, avg(salary)
FROM project p INNER JOIN department d on p.dnum = d.dnumber
INNER JOIN employee e ON e.dno = d.dnumber;
I'm getting one row in the result set... pname = null, avg(salary) = null.
Result set should contain 11 rows because there are 11 projects in the schema.
Can someone point me in the right direction?
Thank you
You are missing the group by:
SELECT pname, avg(salary)
FROM project p INNER JOIN
department d
on p.dnum = d.dnumber INNER JOIN
employee e
ON e.dno = d.dnumber
GROUP BY pname;
In most databases, your version would fail with an obvious syntax error. MySQL only enforces the ANSI standard if you use the ONLY_FULL_GROUP_BY mode (see here).
Use left outer join instead of inner join
Or can you show me your data tables
Do you need the department table in your query?
Does the following query return all the data you need to summarize?
SELECT pname, salary
FROM ( SELECT salary, dno AS dnum FROM employee ) e
NATURAL JOIN project;
If it does, then this might be the summarization you require:
SELECT pname, AVG( salary ) AS average_salary
FROM ( SELECT salary, dno AS dnum FROM employee ) e
NATURAL JOIN project
GROUP
BY pname;

Aggregation MAX COUNT sub query, with joins

I have following query to solve:
"List the Member(s) who are born in and after 1990 and have organised the Hackathons that have received funding from the project(s) that have the highest number of labs co-working on them."
SELECT Member.email, Member.firstName, Member.lastName, Member.dateOfBirth,
Hubs.organiserMember, MAX(LabInProject.projectID)
FROM LabInProject
INNER JOIN Project ON LabInProject.projectID=Project.projectID
INNER JOIN Hackathon ON Project.projectID=Hackathon.fundingProject
INNER JOIN Hubs ON Hackathon.eventID=Hubs.eventID
INNER JOIN Member ON Member.email=Hubs.organiserMember
WHERE LabInProject.projectID = (SELECT MAX(LabInProject.projectID) FROM LabInProject)
GROUP BY Hubs.organiserMember
HAVING Member.dateOfBirth > '1990'
The SELECT MAX gives me the highest projectID (number) in the row, NOT the highest COUNT of projectID.
How do I get the "MAX COUNT" of projectID in table: LabInProject?
I have tried by making a subquery with a derived table: totalCount, but I don't know how to connect this with the joins, it's not working.
HAVING COUNT(*) =
(
SELECT COUNT(projectID) totalCount
FROM LabInProject
GROUP BY projectID
LIMIT 1
)
WHERE LabInProject.projectID = (SELECT MAX(LabInProject.projectID) FROM LabInProject)
You have a Syntax-Error here.
Try to post the closing bracket at the end of the statement.
Consider the below derived table in an inner join with its own derived tables to replace the earlier WHERE condition. This should return multiple projects that share same maximum counts:
...
INNER JOIN
-- OBTAIN PROJECT AND COUNTS CONDITIONED TO THE MAX
(SELECT sub.ProjectID, Count(*) As ProjectIDCount
FROM LabInProject sub
INNER JOIN Project ON LabInProject.projectID=Project.projectID
INNER JOIN Hackathon ON Project.projectID=Hackathon.fundingProject
INNER JOIN Hubs ON Hackathon.eventID=Hubs.eventID
INNER JOIN Member ON Member.email=Hubs.organiserMember
WHERE Member.dateOfBirth > '1990'
GROUP BY sub.ProjectID
HAVING Count(*) IN
-- OBTAIN SCALAR VALUE OF MAX PROJECT COUNT
(SELECT Max(dT.ProjectIDCount) As MaxOfProjectIDCount
FROM
-- OBTAIN PROJECT COUNTS
(SELECT subdT.ProjectID, Count(*) As ProjectIDCount
FROM LabInProject subdT
INNER JOIN Project ON LabInProject.projectID=Project.projectID
INNER JOIN Hackathon ON Project.projectID=Hackathon.fundingProject
INNER JOIN Hubs ON Hackathon.eventID=Hubs.eventID
INNER JOIN Member ON Member.email=Hubs.organiserMember
WHERE Member.dateOfBirth > '1990'
GROUP BY subdT.ProjectID) As dT)
) As temp
ON LabInProject.projectID = temp.projectID
...

sql - Return set with no duplicates from inner join?

Creating a mock help desk ticketing service.
I have a ticket table which holds all tickets created by the customer.
I have a works_on table which holds all tickets which managers have claimed and are working on.
In both tables I have a customerid to identify the owner of the ticket.
In the customer menu, they can check all of their tickets that they created, whether they are open, in the ticket table or being worked on in the works_on table.
My code below is giving me the same ticket from both tables. I only want to see the ticket once. How can I do that?
SELECT * FROM ticket
INNER JOIN works_on
ON ticket.custid = works_on.customerid
Good day,
try using Group By
SELECT * FROM ticket
INNER JOIN works_on
ON ticket.custid = works_on.customerid
GROUP BY ticket.custid
you can also try using DISTINCT
The SELECT DISTINCT statement is used to return only distinct
(different) values
SELECT * FROM ticket
INNER JOIN works_on
ON ticket.custid = works_on.customerid
GROUP BY ticket.custid
This will group the results where the customer ID are the same.
If not the modify the select into a SELECT DISTINCT
You're joining on the wrong columns. When you join on customerid, it finds all the tickets for a customer, and all the works_on rows for that customer, and creates a cross-product between them. You should be joining on the ticket ID, so you get each ticket with its corresponding works_on row.
SELECT *
FROM ticket AS t
INNER JOIN works_on AS w ON t.ticket_id = w.ticket_id
WHERE t.custid = :customer

Rewriting a sub-query into a single query so it can be put into a view in SQL

I have a homework problem where I have this schema:
Emp(eid:integer, ename:string, age:integer, salary:real)
Works(eid:integer, did:integer)
Dept(did:integer, managerid:integer)
And with this, I am supposed to construct a single view entitled Manager giving the eid, ename of an employee and his/her manager's eid and ename. Then I am supposed to say if the view is updatable, and why/why not.
So, I successfully created the query to do get this information:
SELECT
Employee.eid,
Employee.ename,
Manager.mid,
Manager.ename
FROM
(
SELECT Dept.managerid AS mid, ename, did
FROM Emp
INNER JOIN Dept
ON Emp.eid = Dept.managerid
) as Manager
INNER JOIN
(
SELECT ename, Emp.eid, did
FROM Emp
INNER JOIN Works
ON Emp.eid = Works.eid
) AS Employee
ON
Employee.did = Manager.did
AND
Employee.eid != Manager.mid;
But when I add CREATE VIEW Manager AS to the top of the statement to create a view out of it, I end up getting this error: View's SELECT contains a sub query in the FROM clause
For reference, I have uploaded my code to sqlfiddle. The only thing that needs to be done is to add CREATE VIEW Manager AS right before the SELECT statement at the bottom.
I was wondering if there is a way I could somehow refactor this statement to not use a nested SELECT so that I can only use a single view. Unfortunately I am limited to using only one view for my assignment.
Subqueries are an unnecessarily complicated way of going about this. Easier just to join emp to works, work to dept, and then dept back to emp.
select e.*, e2.*
from emp e
inner join works w
on w.eid = e.eid
inner join dept d
on w.did = d.did
inner join emp e2
on d.managerid = e2.eid
updated your fiddle
To create a view from this, you would need to alias the resulting columns, since there are duplicates. eg:
select e.eid as `employee_id`, e.ename as `employee_name`, e2.eid as `manager_id`, e2.ename as `manager_name`
instead of select e.*, e2.*