Learning to use join between 2 tables - sql

I got two tables :
STUDENT with the columns ID, name, surname, class
SCORE with columns Student ID, Score_date, Score, Discipline
Display all students and their scores in Mathematics (whether or not they have a score):
SELECT Id, Name, Score
FROM STUDENT, SCORE
WHERE SCORE.Studentid = STUDENT.id
AND SCORE.Discipline = 'Mathematics';
How to do these queries using JOIN? I've tried to understand it on several sites, but it's still not clear (I'm new in SQL), can someone explain simply how it works?

This:
FROM student, score WHERE student.id = score.studentid
is the syntax we used in the 1980s. In 1992 the SQL standard invented explicit joins:
FROM student INNER JOIN score ON student.id = score.studentid
If you are in a class where you are taught using the 1980s syntax, I'd say quit that class.
Anyway, both are joins. Inner joins at that. You join the tables student and score on the sudentid and only keep matches (i.e. if a student doesn't have any score row, you don't select that student).
Your second query doesn't contain a join, but a lookup with NOT EXISTS.
Your third query contains an inner join again. This, however, does not match the task where you are asked to also show students that are not in Mathematics. You'd need an outer join there:
SELECT st.id, st.name, sc.score AS math_score
FROM student st
LEFT OUTER JOIN score sc ON sc.studentid = st.id AND sc.discipline = 'Mathematics';

Related

How to display the desired rows of two tables using a subquery?

My subquery:
select studentName, Course.dataStart
from Student,
Course
where Student.id in (select Course.id from Course);
I need a solution to this (above) subquery (not a join)
Why does the SQL subquery display one date for each name? (task: display the names of students from the Student table and the course start date from the Course table using a subquery)
With the help of Join, I get it as it should: (but I need to do it with a subquery)
You seem to be using implicit join syntax, but really you should be using an explicit inner join:
SELECT s.studentName, c.dataStart
FROM Student s
INNER JOIN Course c
ON c.id = s.course_id;
If you really wanted to use the implicit join syntax, it should be something like this:
SELECT s.studentName, c.dataStart
FROM Student s, Course c
WHERE c.id = s.course_id;
But again, please use the first version as its syntax is considered the best way to do it.
You can apply join :
SELECT S.studentName, C.dataStart
FROM Student S
INNER JOIN Course C
ON C.id = S.course_id;
With Sub query:
Select studentName, (Select Course.dataStart from Course
Where Course.id = course_id)
From Student
Asuming that Course.Id field is Student.Id (although it seems strange to me), I think the only way to get the results you want with a subquery would be using it in the SELECT clause:
select studentName, (SELECT Course.dataStart FROM Course WHERE Course.Id = Student.Id)
from Student
This would fail if you have more than 1 row in Course per Student, in that case you could use (SELECT DISTINCT Course.dataStart...)

I need an JPA/SQL expert: EXISTS query on an Inner Join returns wrong result

I have three tables and want to:
Select all students from the first table,
that have at least one connection to the school in district '999' in the second table
and at least one connection to the teacher with social_number '101'
and at least one to the teacher with number '103' in the third table.
The tables are connected through the second table.
I created an online sql compiler to show the problem:
http://tpcg.io/FIoO79xi
This query works fine and as expected, until I add the third EXISTS Command where I search for a connection to teacher '103'. Then it doesn't return student A anymore, altough he has a connection to teacher '103'
I found a workaround by adding joins in the Exists sub-query:
http://tpcg.io/0sza7t5g
but since my real database tables have many million entries, this would lead to joining the three tables in every row that the sub-query goes through and this can take very long if it only finds a fitting entry at the end of the table.
I think the problem is here at the sub-query: WHERE th1.school_id = th.school_id where I'm trying to find a connection from the third table teacher to the at the beginning joined together table. If I search for a connection to teacher 102 instead of 103, the query works and returns student A:
http://tpcg.io/2tHIEk3V
Because teacher 101 and 102 have the same school_id.
But how can I write that differently so that the query also finds student A when I search for a connection to teacher 101 and 103? Student A has a connection to both, so it should be possible somehow with exists...
Add: I can't use three seperate queries and then use the Intersect command on them, since I'm translating that SQL into a JPA query. JPAdoesn`t know intersect...
The 1st condition:
at least one connection to the school in district '999' in the second
table
needs a join of student to school.
The 2nd and 3rd conditions:
at least one connection to the teacher with social_number '101'
and at least one to the teacher with number '103'
need 2 separate joins of student to school and teacher:
SELECT s.name
FROM student s
INNER JOIN school sc on s.student_id = sc.student_id AND sc.district = 999
INNER JOIN school sc1 on s.student_id = sc1.student_id
INNER JOIN teacher t1 on t1.school_id = sc1.school_id AND t1.social_number = 101
INNER JOIN school sc2 on s.student_id = sc2.student_id
INNER JOIN teacher t2 on t2.school_id = sc2.school_id AND t2.social_number = 103
Note that a condition like social_number in (101, 103) will not work because it would return results even if only 1 of the conditions was satisfied.
This is why you need 2 joins to school and teacher.
Also all the joins must be inner because you want to satisfy all 3 conditions.
See the demo.
Results:
| name |
| ---- |
| A |
You need 2 teacher table joins
SELECT name
FROM student
left JOIN school sc1 on #student.student_id = sc1.student_id
left JOIN teacher th1 on sc1.school_id = th1.school_id and th1.social_number=101
left JOIN teacher th2 on sc1.school_id = th2.school_id and th1.social_number=103
where sc1.district=999
Why so complicated ?
`SELECT name
FROM student
LEFT JOIN school sc1 on student.student_id = sc1.student_id
LEFT JOIN teacher th1 on sc1.school_id = th1.school_id
WHERE sc1.district = '999'
AND th1.social_number in('101','103')`
doesn't do the trick ?
http://tpcg.io/eGeWjkOf
The whole joining is unnecessary when we ask for a connection between the teacher and the student in an additional WHERE clause.
The Exists subquery then looks like this, instead of a Join I use an additional where to make sure the teacher.school_id is the same as the school.school_id of the school the student goes to:
EXISTS (
SELECT *
FROM teacher th
WHERE th.social_number = '103'
AND th.school_id in (SELECT school_id FROM school WHERE student_id = student.student_id ))

SQLITE3 Inner Join Returning Too Many Tuples

I have 4 tables in sqlite3:
students(student_id, student_name)
instructors(instructor_id, instructor_name)
courses(course_id, course_name)
and
enrollments(enroll_id, student_id, instructor_id, course_id)
With the last 3 columns having a foreign key reference to the relevant columns in the first 3 tables
When I try to do a query that shows only the student’s name, instructor’s name and course name where an enroll_id is equal to 001 for example
SELECT students.student_name, instructors.instructor_name, courses.course_name
FROM users, instructors, courses INNER JOIN enrollments
WHERE enrollments.enroll_id = 001;
I'm getting a lot of data from all tables, but not a single tuple with just the relevant enroll data assigned to enroll_id 001. Any help is appreciated
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax. The right way to express this query is:
SELECT s.student_full_name, i.instructor_name, c.course_name
FROM enrollments e JOIN
instructors i
ON e.instructor_id = i.instructor_id JOIN
courses c
ON e.course_id = c.course_id JOIN
students s
ON e.student_id = s.student_id
WHERE e.enroll_id = 001;
The use of table aliases is highly recommended. It makes the query easier to write and to read.
Try this:
SELECT students.student_full_name, instructors.instructor_name, courses.course_name
FROM users, instructors, courses, enrollments
WHERE enrollments.enroll_id = 001
and enrollments.student_id = users.student_id
and enrollments.instructor_id = instructors.instructor_id
and enrollments.course_id = courses.course_id;

Where SQL column value not found in other column

I've read similar questions and I think I am doing it correct, but I just wanted to make sure my SQL is correct. (Still new to SQL)
I have 2 different tables
Students
id, name, address
Staff
id, name, address
I need to find the total number of students (who are not also staff)
SO I have the following SQL
create view nstudents as
select students.id
from students
LEFT JOIN staff ON staff.id = students.id;
Then I run the count(*) on the view.
Can someone confirm my SQL is correct or is there better way to do it?
Your LEFT JOIN doesn't eliminate students who are also staff, but it could be useful in achieving your goal. LEFT JOIN provides you with all results from the left table and matching results from the right table, or NULL results if the right table doesn't have a match. If you do this:
select count(*)
from students
LEFT JOIN staff ON staff.id = students.id
WHERE staff.id IS NULL;
I expect you'll get what you're looking for.
You might find it more natural to do something like this:
create view nstudents as
select s.id
from students s
where not exists (select 1 from staff st where st.id = s.id) ;
This should have the same performance as the left join.

SQL count after joining two tables

I am newbie to SQL, I would like to come up with a count, assume this example with 2 tables:
School(schoolID, name,....)
Student(StudentID, SchoolID, ...)
I tried:
SELECT COUNT(studentID)
FROM School s, Student t
WHERE s.schooldID = t.schoolID
How can I get a count of all students across all schools?
Since you have the school ID in the student table, it doesn't appear to me that you need to join to school at all. Just select a count from the student table and group by schoolID:
SELECT schoolID, COUNT(*) AS numStudents
FROM student
GROUP BY schoolID;
The only reason you'd need to join to School is if you want other information, such as school name and so on. If you just want the school id and number of students, the above will work.
To complete that last thought, possibly irrelevant to your question. If you did want school name, you just do an inner join and put school.name in your select statement, along with the count from the student table and group by school ID still:
SELECT s.name, st.COUNT(*) AS numStudents
FROM student st
JOIN school s ON s.id = st.schoolID
GROUP BY s.id;
If you want to get the count per school, you need a group by. Also, usually we prefer ANSI style joins, since in fact all database systems support them nowadays and they easier to read and maintain:
select count(t.studentID)
from Student t
join School s /* added join for your convenience, not necessary here */
on s.schooldID = t.schooldID
group
by t.schoolID