I am newbie in SQL and practicing queries for my university assignments...I have three tables in the database:
1. student:
studentid pk
fname
school
2. books:
bookid pk
bookname
3. issue:
issueid pk
studentid fk
bookid fk
fine
and I am trying to solve this query:
select the bookname and the average fine for those students who have issued two or more books.
I have tried using nested INNER JOINs as:
SELECT fname,bookname,AVG(fine) FROM
student INNER JOIN ( books INNER JOIN issue ON books.bookid=issue.bookid) ON
student.studentid=issue.issueid
GROUP BY fname
HAVING COUNT(bookid)>1;
but failed.Is there any mistake or is it totally wrong to nest JOINs as above? Or please hint me if there is an another way to do this using JOIN.
You can do two separate joins:
SELECT fname,bookname,AVG(fine)
FROM student
INNER JOIN issue ON student.studentid=issue.issueid
INNER JOIN books ON books.bookid=issue.bookid
GROUP BY fname
HAVING COUNT(bookid)>1;
Another possibility is to join on several tables in the same INNER JOIN:
SELECT fname,bookname,AVG(fine)
FROM student
INNER JOIN (issue, books) ON (student.studentid=issue.issueid AND books.bookid=issue.bookid)
GROUP BY fname
HAVING COUNT(bookid)>1;
The reason your query was wrong is simply that you did not use the right syntax...: there is no such thing as nested joins.
This page is the MySQL documentation page for joins. You will find many examples of how to handle joins.
This one should work. You can append INNER JOINs after each other, and use the values of any previously called tables after the ON parameter.
SELECT student.fname, books.bookname, AVG(issue.fine)
FROM student
INNER JOIN issue ON issue.studentid = student.studentid
INNER JOIN books ON books.bookid = issue.bookid
GROUP BY student.fname
HAVING COUNT(books.bookid)>1
Related
I’m studying sql command line, and using command in mysql via terminal. I’m studying INNER JOIN, and I found it easy enough, but I have a doubt that I must solve otherwise cannot manage to pass to other commands.
I have these four tables: departments, employees, employees_projects, projects
These tables have the following content:
departments:
id int
name varchar(60)
employees:
id int
first_name varchar(60)
last_name varchar(60)
salary int
department_id int
employees_projects:
project_id int
employee_id int
projects:
id int
title varchar(60)
start_date date
end_date date
budget int
When I want to use INNER JOIN to join two tables I simply use it this way:
SELECT employees.first_name, employees.last_name, departments.name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;
When I want to join three tables I use the following:
SELECT employees.first_name, employees.last_name, departments.name, employees_projects.project_id
FROM ( (employees
INNER JOIN departments ON employees.department_id = departments.id)
INNER JOIN employees_projects ON employees.id = employees_projects.employee_id);
Here is my question: As you can see the result of the last line will give me employees.first_name, employees.last_name, departments.name, employees_projects.project_id, this mean I would get the employee’s name, surname, department and id of the project they are working on. Now, considering the tables we have above, I cannot manage to create a one line SQL query that give me as a result employees.first_name, employees.last_name, departments.name, projects.title. This mean one query that would give me employee’s name, surname, department and the project’s name they are working on.
Is it possible to achieve this in one line query?
mysql> Thank you everybody!
EDITING THE POST:
I created the following line:
SELECT employees.first_name, employees.last_name, departments.name, projects.title FROM ( (employees, projects INNER JOIN departments ON employees.department_id = departments.id) INNER JOIN employees_projects ON projects.id = employees_projects.project_id AND employees_projects.employee_id = employees.id);
But unfortunately I'm receiving this error, and it's strange because looks the correct column:
mysql> SELECT employees.first_name, employees.last_name, departments.name, projects.title FROM ( (employees, projects INNER JOIN departments ON employees.department_id = departments.id) INNER JOIN employees_projects ON projects.id = employees_projects.project_id AND employees_projects.employee_id = employees.id);
ERROR 1054 (42S22): Unknown column 'employees.department_id' in 'on clause'
mysql>
You are probably familiar with arithmetic notation. You can make an arithmetic expression with any number of terms:
a + b + c + d
The first term has nothing before it. Each term has a + between it. There really isn't a "main" term, because addition has the algebraic property of commutativity. The expression has the same result as:
c + a + d + b
Or any other ordering of the terms.
In SQL, joins are similar. You can in theory join any number of tables.
<table> INNER JOIN <table> ON <condition>
INNER JOIN <table> ON <condition>
INNER JOIN <table> ON <condition>
And you can keep adding more after that if you need to. (I said in theory because MySQL or any other SQL product is just one implementation of the language and it may have a practical limit. In MySQL's case, the limit is 63 tables per query but that's not the fault of the language, it's just how MySQL's code implements joins.)
FROM is not part of the expression, and it doesn't name any table as the "main" table. Inner join has the property of commutativity, like addition in arithmetic. In fact, MySQL can reorder the tables itself as it runs your query, if it turns out to make the query have better performance.
You tried this join:
FROM ( (employees, projects INNER JOIN departments
ON employees.department_id = departments.id)
INNER JOIN employees_projects
ON projects.id = employees_projects.project_id
AND employees_projects.employee_id = employees.id);
You're mixing two syntax forms, and it causes a problem.
Joins with comma are from 1989, and these still work. But they couldn't do OUTER JOIN and so the syntax was changed in 1992 to have the INNER/OUTER JOIN keywords.
But the problem is that the syntax with the INNER/OUTER JOIN keywords has higher precedence than comma. So it's as if your query were joining projects and departments before the query engine has even acknowledged that employees is part of the query. When it checks the ON condition that references employees, it doesn't know about that table.
This is in fact documented: https://dev.mysql.com/doc/refman/8.0/en/join.html search for "JOIN has higher precedence than the comma operator" near the bottom of the page.
The solution is to use only the 1992 style syntax consistently. I would write it the way #Adamszsz writes the query in the other answer.
Use need something like this :
select emp.first_name,emp.last_name,d.name,p.title , p.id from employees emp
join departments d on d.id = emp.department_id
join employees_projects empp on empp.employee_id = emp.id
join projects p on p.id = empp.project_id
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
I have two sql queries and I need the intersect between then. I know mysql does not have the intersect operand, so how could I do it? Tried some solutions I found online but they all return some syntax error. The queries are:
SELECT person_name FROM person NATURAL JOIN (
SELECT * FROM movie NATURAL JOIN role WHERE movie_name = 'Alien'
) alias1
SELECT person_name FROM person WHERE gender = 'f'
You can JOIN all three tables together, and apply both WHERE clauses.
Here is an example. It assumes that your movie table joins to your role table on a column called movie_id, as well as an assumption that you have a person_id column in role and person to join them. You'll need to change this query to use the columns that your tables use.
SELECT
p.person_name
FROM
movie m
INNER JOIN role r
ON (m.movie_id=r.movie_id)
INNER JOIN person p
ON (r.person_id=p.person_id)
WHERE
m.movie_name='Alien'
AND p.gender='f'
Edit: I've used INNER JOIN here, with a guess at the columns to join on, as opposed to keeping the OP's NATURAL JOIN. As the comments to the OP have mentioned, best practice is to explicitly identify the joins, and not rely on a NATURAL JOIN.
I have two tables:- PERSON and DATA. What I want to do is fetch all details from PERSON table and only two columns from DATA table only when PERSON.personId = DATA.personId.
I am using this query:-
SELECT *
FROM PERSON AND SELECT DATA.value, DATA.field
FROM DATA where PERSON.personId = DATA.personId;
But I think this is wrong syntax. Can anyone tell me what is the right syntax for it.
SELECT p.*,d.column1,d.column2
FROM Person p
JOIN Data d
ON p.personId = d.personId
WHERE <Condition>
In this query person with all columns and data with your desire column you can fetch by this query.
Something like this:
select
P.*,
D.value,
D.field
from Person P
join Data D on P.PersonID = D.PersonID
change P.* to the specific columns that you need but P.* will get everything from the Person table.
check this post out LEFT JOIN vs. LEFT OUTER JOIN in SQL Server to learn about JOINS, the diagram is good to understand what the different ones do
Its really easy, Just execute this query:
SELECT
PERSON.*,
DATA.value,
DATA.field
FROM
PERSON INNER JOIN DATA USING (`personId`);
It selects all fields of PERSON + value and field from DATA.
Also it uses personId to join the two tables.
Fill free to ask if you need more info.
You can use join (LEFT JOIN)
SELECT * FROM PERSON LEFT JOIN DATA ON PERSON.personId = DATA.personId
Hope it will help you
Here's the correct syntax for achieving what you've asked for:
SELECT PERSON.column1,PERSON.column2,PERSON.columnN,DATA.value
FROM PERSON
INNER JOIN DATA
ON PERSON.personId = DATA.personId
Line#1: lists the columns that you want to select with references to their parent tables.
Line#2 and 3: are the two tables that you want to select from and join with
Line#4: is the join condition between the two tables (with matching IDs or other information)
I am using the 3 following tables:
First table
id
response
Second table
responseid
patientid
Third table
patientid
The relationship between first and second table is on id and responceid.
The relationship between third and second is on patientid.
Now I need to retrieve values from these tables like all values from first and third tables with the help of matching with patientid from second and 3rd table.
How can I do this?
Basically if all of the columns that defines their relationship are not nullable, then INNER JOIN will suffice. But if they are nullable and you still want to display all records from firstTB, you need to use LEFT JOIN instead of INNER JOIN.
SELECT a.*, b.*, c.*
FROM firstTB a
INNER JOIN secondTB b
ON a.ID = b.responceID
INNER JOIN thirdTB c
ON b.patientID = c.patientID
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
You're probably looking for INNER JOIN or JOIN in general:
SELECT
response.id,
response.responce,
patient.patientid
FROM
`response_table` as `response`
INNER JOIN
`relation_table` as `relation`
ON
relation.responceid = response.id
INNER JOIN
`patient_table` as `patient`
ON
relation.patientid = patient.patientid
try
SELECT first.*
, third.*
FROM first
INNER JOIN second ON ( second.responseid = first.id )
INNER JOIN third ON ( third.patientid = second.patientid )
;
honestly, and no insult intended, if you have difficulties in coming up with queries like this one on your own, consider some training on db basics and db development, the sooner the better (just hoping i haven't blundered myself ... ;-)).