SQL Query with multiple conditions not working - mysql

Okay so this is my best attempt at making a query. It currently executes but returns nothing the other attempts have not worked.
The joins are wrong I believe and I'm not sure how to fix them or do this right
In this query I am trying to get the activity details with staff assigned to those activities matching all conditions below.
The staff and activities are linked in the Allocation table with a Staff ID assigned to an Activity ID there.
--Teach at least 2 modules during 2019 in a certain campus
The staffID must occur at least twice in the Teach table at the field StaffID
The spaID 5 or 6 would correspond to the campus so teach two modules at this time and ID.
--Supervise more than 1 colleagues
This is in the staff table with SupervisorID being a foreign key of StaffID in the same table.
So the Staff ID allocated to the activity needs to supervise more than one colleague with their ID appearing in SupervisorID more than once.
--The related activity is internal one
The activity is internal if it equals to 1.
So to sum it up the activity details should only appear in the query results if it has staff matching all the conditions above
SELECT Activity.AcID, Activity.Title, Activity.CaID, Activity.Internal, Activity.BuID, Budget.Amount FROM Activity
INNER JOIN Budget ON Activity.AcID = Budget.BuID
INNER JOIN Allocation ON Activity.AcID = Allocation.AcID
INNER JOIN Staff ON Allocation.StaffID = Staff.StaffID
INNER JOIN Teach ON Allocation.StaffID = Teach.StaffID
WHERE Activity.Internal=1 AND
Allocation.StaffID IN (
SELECT Staff.SupervisorID
FROM Staff
GROUP BY StaffID
HAVING COUNT(Staff.SupervisorID=Allocation.StaffID) >1)
AND Allocation.StaffID IN (
SELECT Teach.StaffID
FROM Teach
WHERE Teach.Year='2019' AND Teach.SpaID=5 OR 6
GROUP BY Teach.StaffID
HAVING COUNT(Allocation.StaffID=Teach.StaffID) >=2);
Table details are below if you want to look at them for more details
Table Activity -- AcID, Title, CaID, BuID, Status, Started, Ended Internal
Table Allocation -- StaffID, AcID
Table Budget -- BuID, Amount, Approver, Payee, Status
Table Campus -- CaID, Address, GmName, Country, Status
Table Classroom -- RmID, Capacity, CaID, Location, Type, Status
Table Module -- ModuleID, Module Name, DeptID, Programme, TMode, Date_of_Firstoffer
Table SpaceAssign -- SpaID, RmID, TID, Manager, Approved
Table Staff -- StaffID, Title, FirstName, LastName, DeptID, CaID, Joined, LeftD, Current, Salary, ContractType, SupervisorID
Table Teach -- TID, ModuleID, StaffID, SpaID, Semester, Year
I have tried my best to explain this well sorry for any confusion.

Without data It's very tough to find a solution. Please try this:
SELECT Activity.AcID, Activity.Title, Activity.CaID, Activity.Internal, Activity.BuID, Budget.Amount FROM Activity
INNER JOIN Budget ON Activity.AcID = Budget.BuID
INNER JOIN Allocation ON Activity.AcID = Allocation.AcID
INNER JOIN Staff ON Allocation.StaffID = Staff.StaffID
INNER JOIN Teach ON Allocation.StaffID = Teach.StaffID
WHERE Activity.Internal=1 AND
Allocation.StaffID IN (
SELECT Staff.SupervisorID
FROM Staff
GROUP BY SupervisorID
HAVING COUNT(*) >1)
AND Allocation.StaffID IN (
SELECT Teach.StaffID
FROM Teach
WHERE Teach.Year='2019' AND Teach.SpaID=5 OR 6
GROUP BY Teach.StaffID
HAVING COUNT(*) >=2);

It is hard to tell without having access to the data but you can try to change the inner joins to left joins and also:
This
WHERE Teach.Year='2019' AND Teach.SpaID=5 OR 6
Should be
WHERE Teach.Year='2019' AND (Teach.SpaID=5 OR Teach.SpaID=6)
This looks incorrect as well:
INNER JOIN Budget ON Activity.AcID = Budget.BuID
Should be:
INNER JOIN Budget ON Activity.BuID = Budget.BuID

Related

How to select an employee in SQL, compared to another employee

I'm new here on the site, I'm learning databases independently, and there's a question I've been trying for a long time, and I decided to ask it here
The question has such a database:
Person (p-id, name, title, hourly-rate, title)
Topics (t-name, description)
Workshops (p-id, t-name, hourly-credit)
Employees (e-id, name, address, mobile)
EmpTraining (e-id, p-id, t-name)
Persona - The lecturer has a unique ID, name, degree, cost per hour
Topics - the topics in which workshops are delivered. Each topic has a unique name (time management, budget management, etc.) and description.
Workshop - A workshop delivered by a specific lecturer on a specific topic. (Several lecturers can deliver a workshop on the same topic and a lecturer can deliver workshops on different topics) Each workshop is defined as the number of hours that entitle the employee to the training allowance.
Employee - The employee has a unique ID, address and telephone name.
EmpTraining - Each employee is documented in all the workshops he has taken
Example of the database I built, I want to point out that the example here is from a test I failed, the database itself I added is just an example, it does not belong to the exercise itself, but that way it is easier for me to explain, and that way easier to understand.
https://www.db-fiddle.com/f/wrDLMHhsquiFQmZT7uS3Z9/0
I need to write it in code in SQL, two things:
Return the names of the employees who have undergone at least the same series of workshops as the outstanding employee whose employee number is 100.
In this question I have to return the names of all the workers, who did all the workshop that a worker with number 100 did
i try to write, i dont thing that is right, because i am not sure how to select same series of workshops:
select name
from Persona as p1, Workshops as w1
where exist {
select *
from Persona as p2, Workshops as w2
where p2.p-id = 100 AND w1.p-is != w2.p-id and w1.t-name = w2.t-name
}
Return the names of all the employees who have accumulated the number of hours of entitlement to training higher than that of the outstanding employee whose employee number is 100.
In this question I have to return the names of all the employees, that the number of hours they did for training is greater than the hours that employee number 100 did
I did not make it 2, was hard to me.
I would be very happy to help, I have been trying to do this for two weeks, thank you very much.
I want to point out that I do not have the tables with the data, this is a question from a test I had, I do not know how to make tables for it, I need an answer that is similar to the solution, like a pseudo-code
As per your example, I'm expecting by Employees you mean Employees table and by no of hours they did you mean hourly_credit in Workshop table, then below are the queries -
1st Query Can be like -
SELECT e.e_id FROM Employees e inner join EmpTraining et on e.e_id = et.e_id where et.t_name in (
SELECT t_name FROM EmpTraining where e_id = 100
)
GROUP BY et.e_id
having count(DISTINCT et.t_name) >= (SELECT count(DISTINCT t_name)
FROM EmpTraining where e_id = 100);
Here first I'm filtering rows on the basis of workshop name of employee id 100, using below sub query
SELECT t_name FROM EmpTraining where e_id = 100
Then if we group the result set and then compare distinct count with the distinct count of workshops of employee hundred we can get the employees set we want
Note: Result will contain employee with id - 100 as well to exclude it from the result we can add another condition in where like -
AND e.e_id != 100
2 nd Query
SELECT any_value(e.name) as name
FROM Employees e inner join EmpTraining et on e.e_id = et.e_id inner join Workshops w on et.t_name = w.t_name
GROUP BY et.e_id
having sum(w.hourly_credit) > (
SELECT sum(w.hourly_credit)
FROM Workshops w inner join EmpTraining etg on etg.t_name = w.t_name
where etg.e_id = 100
);
Here I'm grouping rows of EmpTraining on the basis of e_id and comparing sum of hourly_credit with the sum of hourly_credit of employee id 100 EmpTrainings

Why does my Query return "Empty set (0.00 sec)"?

SOLVED-run UPDATE building SET building_name = "Main Street Building" WHERE building_id = 2;
From there, the task 3 query will return proper results.
Task One:
Query:
SELECT first_name, last_name, building_name, room.room_id, meeting_start,meeting_end
FROM meeting, person, person_meeting,room, building
WHERE room.room_id=meeting.room_id
AND meeting.meeting_id=person_meeting.meeting_id
AND person.person_id=person_meeting.person_id
AND room.building_id=building.building_id
AND person.first_name='Tom'
AND person.last_name='Hanks';
Task Two:
Query:
SELECT first_name, last_name, building_name, room.room_id, meeting_start,meeting_end
FROM meeting, person, person_meeting,room, building
WHERE room.room_id=meeting.room_id
AND meeting.meeting_id=person_meeting.meeting_id
AND person.person_id=person_meeting.person_id
AND room.building_id=building.building_id
AND meeting.meeting_id=2;
Task Three:
Query:
SELECT first_name, last_name, building_name, room.room_id,meeting.meeting_id, meeting_start, meeting_end
FROM meeting, person, person_meeting,room, building
WHERE room.room_id=meeting.room_id
AND meeting.meeting_id=person_meeting.meeting_id
AND person.person_id=person_meeting.person_id
AND room.building_id=building.building_id
AND building_name='Main Street Building';
Task Four:
Query:
SELECT count(person_id) 'Count of meeting attendees', meeting.meeting_id,meeting_start,meeting_end
FROM meeting, person_meeting
WHERE meeting.meeting_id=person_meeting.meeting_id
GROUP BY meeting.meeting_id;
Task Five:
Query:
SELECT first_name, last_name, meeting.meeting_id, meeting_start, meeting_end
FROM meeting INNER JOIN person_meeting ON meeting.meeting_id=person_meeting.meeting_id
INNER JOIN person ON person.person_id=person_meeting.person_id
AND meeting_start<'2016-12-25 12.00.00';
Task 1,2,4,5 and 5 all run perfectly. if you all need the task prompts, let me know.
Note: I haven't test this yet.
I changed the queries based on our recent interaction.
This is your original
SELECT first_name, last_name, building_name, room.room_id,meeting.meeting_id, meeting_start, meeting_end
FROM meeting, person, person_meeting,room, building
WHERE room.room_id=meeting.room_id
AND meeting.meeting_id=person_meeting.meeting_id
AND person.person_id=person_meeting.person_id
AND room.building_id=building.building_id
AND building_name='Main Street Building';
This is the way I would try to build it
Based on page 2 and 3 in the document, you provided, https://snhu.brightspace.com/d2l/lor/viewer/viewFile.d2lfile/76437/9523,2/, I would do the following:
First, I would obtain information about the building.
SELECT building_id
FROM building
WHERE building_name like '%Main Street Building%';
Note: I am assuming that the building name is correct. However, just in case, I am using the wildcard % before and after the name
Next, I would obtain the information about the room:
SELECT b.building_name, r.room_id
FROM room r
LEFT JOIN building b
ON r.building_id = b.building_id
WHERE b.building_name like '%Main Street Building%';
Following that, I would obtain the information about the meeting:
SELECT b.building_name, r.room_id, m.meeting_id, m.meeting_start, m.meeting_end
FROM room r
LEFT JOIN building b
ON r.building_id = b.building_id
LEFT JOIN meeting m
ON r.room_id = m.room_id
WHERE b.building_name like '%Main Street Building%';
Finally, I would obtain the information of the IDs of people that will be in that meeting and show their names:
SELECT b.building_name, r.room_id, m.meeting_id, m.meeting_start, m.meeting_end, p.first_name, p.last_name
FROM room r
LEFT JOIN building b
ON r.building_id = b.building_id
LEFT JOIN meeting m
ON r.room_id = m.room_id
LEFT JOIN persom_meeting pm
ON m.meeting_id = pm.meeting_id
LEFT JOIN person p
ON pm.person_id = p.person_id
WHERE b.building_name like '%Main Street Building%';
If by any chance, these queries do not work, I would advice that you ensure that the relationships exists between the tables.
This means that there should be a building_id match, a room_id match, a meeting_id match and a person_id match between the tables. Plus, I would check that the building name is spelled correctly since its case-sensitive.
The reason I use LEFT JOINs is so I can display all the information of the previous tables (all the rows) plus the records in which the IDs match the foreign keys IDs. As explained here: http://www.acarlstein.com/?p=4168
Also, in http://www.acarlstein.com/?p=4194, I am showing how a Two Left (Outer)Joins would work.
However, in your case, it is more like a chain that is being build so it doesn't match the diagram but you can perhaps get the idea of what I mean.

Return all courses a student is taking (Many to Many SQL Database example)

I'm fairly new to MySQL, and trying to understand the many-to-many relationship since these examples can popup in interviews
There are 3 tables, and since a Student can have many courses and a Course can have many students, this is a Many-to-Many relationship right?
The tables are
Student- has student ID, name, date of birth, and department.
Courses- Has ID, Name of course
Student_Courses- Has student_id, course_id
How would I display these 2 questions-
1) Given a studentID, return all the names of the courses the student is taking
2) Return the name of students who is taking X amount of courses or more (Ex. 4 or more courses).
Im trying to write queries on these, but I'm stuck...
In the case of selecting all of the courses for a given student ID you could try the following, which will return one row for each Course a Student is associated with.
select
s.name as StudentName,
c.name as CourseName
from `Student` as s
inner join `Student_Course` as sc on (sc.student_id = s.ID)
inner join `Course` as c on (c.ID = sc.course_id)
where
(s.`ID` = 'given_Student_ID_here')
;
As for selecting a list of the names of Students taking N or more courses, for this you might use an aggregating sub-select as a WHERE clause in which we reference one of the outer tables (i.e. [Student]) so that the result of the aggregation is personalised per Student record:
select
s.name as StudentName
from `Student` as s
where
(
(
select count(*)
from `Student_Course` as sc
inner join `Course` as c on (c.ID = sc.course_id)
where (sc.student_id = s.ID)
) >= 4
)
;
You might also consider an alternative approach to this second problem by using the GROUP BY and HAVING clauses:
select
s.name as StudentName
from `Student` as s
inner join `Student_Course` as sc on (sc.student_id = s.ID)
inner join `Course` as c on (c.ID = sc.course_id)
group by
s.name
having
count(*) >= 4
;

How to join any number of tables in MySQL?

I am having a major problem joining 5 tables because each table only has 1 column in common with only 1 other table.
Here are my tables and columns in each table:
TABLE (COLUMNS)
person (person_id, first_name, last name)
building (building_id, building_name)
room (room_id, room_number, building_id, capacity)
meeting (meeting_id, room_id, meeting_start, meeting_end)
person_meeting (person_id, meeting_id)
OK, now here is what I am trying to do (pasted from a homework assignment):
Construct the SQL statement to find all the meetings that person_id #1 has to attend. Display the following columns:
Person’s first name
Person’s last name
Building name
Room number
Meeting start date and time
Meeting end date and time
Now I know how to join 2 tables but I have no idea how to pull info from 5 different tables like this.
I tried looking up how to do this and it just says to do a UNION command, and I am just learning and have yet to cover that.
As UNION is used to combine the result from multiple SELECT statements into a single result set, you don't need it for this scenario. You have to join all the tables one by one based on their Id.
SELECT P.First_Name, P.Last_Name, B.Building_name, R.Room_Number,
M.Meeting_Start, M.Meeting_End FROM Person P
JOIN Person_Meeting PM ON P.Person_Id = PM.Person_Id
JOIN Meeting M ON PM.Meeting_Id = M.Meeting_Id
JOIN Room R ON M.Room_Id = R.Room_Id
JOIN Building B ON R.Building_Id = B.Building_Id
WHERE P.Person_Id = 1

Listing later dates in comparison to another entry in SQL

How would I list the students who started later than start year of student with id = 8871?
This is what I have so far:
SELECT sid s1
FROM Student
WHERE s1.started <= sid = '8871';
I went to this link for some reference but I'm still having issues:
Query comparing dates in SQL
Student Table has:
Student (Lastname, Firstname, SID, Started)
any help would be great
I'd use a self join where one side of the join contains the students you want and the the reference student 8871:
SELECT a.*
FROM student a
JOIN student b ON b.sid = '8871' AND a.started > b.started