How to merge data from multiple tables in SQL - sql

Guess I am in a complex situation. Heres the scene.
I have 3 tables in SQL Server.
Enrollment, Student, Course. (FYI, there are no foreign keys)
The table columns are
Student - StudentId, StudentName
Course - CourseId, CourseName
Enrollment - EnrollmentId, StudentId, CourseId, CourseResult
Sample Data
Student - s1, Sid
Course - c1, Science
Enrollment - 1, s1, c1, 80
I would want a SQL query that selects data like below
1, s1, Sid, c1, Science, 80
I did it hard way in the DAL layer with multiple calls to database. But would like to do it in one call, and in DB.
Any one for the rescue!

Use a join.
select enrollment.*, student.*, course.* from enrollment
inner join Student on enrollment.studentId = student.studentId
inner join Course on enrollment.courseId = course.courseId

There actually are foreign keys in your data model. They may not be marked as such in the db or you don't realize it. I also think it would become clearer if in your list you put the Enrollment table second, between Student and Course. Enrollment is the table that links a student to a course.
I think you just want an inner join on the three tables like this:
SELECT e.EnrollmentId, s.StudentId, c.CourseId, c.CourseName, e.CourseResult
FROM Student AS s
JOIN Enrollment AS e ON s.StudentId = e.StudentId
JOIN Course AS c on e.CourseId = c.CourseId

Seems like a few simple JOINs would do it...
select
e.EnrollmentId
,s.StudentId
,s.StudentName
,c.CourseId
,c.CourseName
,e.CourseResult
from Enrollement e
inner join Course c on e.CourseId = c.CourseId
inner join Student s on e.StudentId = s.StudentId

Try:
SELECT e.EnrollmentId, s.StudentId, s.StudentName, c.CourseId, c.CourseName, e.CourseResult
FROM Student s JOIN
Enrollment e ON s.StudentId = e.StudentId JOIN
Course c ON e.CourseId = c.CourseId

Related

Sql select clause with three table

I am trying to write a sql query to show student list for each course.
The diagram below show the database relationship.
The SQL query I have written is:
select * from Courses
inner join Enrollments on Enrollments.CourseId = Courses.CourseId
inner join Student on Enrollments.StudentId = StudentId
where Courses.CourseId = 1
The issue is that i am getting returned alot more data than I expected as only one student is registered for the course but i get ten entries. I am not sure if i have done somethings fundamental wrong or is my query the issue.
This is the data
This is the result
I expected only two rows to be returned.
Thanks
Every column in your query must be qualified with the table's name.
You did not qualify the column StudentId in this join:
inner join Student on Enrollments.StudentId = StudentId
If you did you would find the error which is that there is no column StudentId in the table Student and you should use the column Id:
select * from Courses
inner join Enrollments on Enrollments.CourseId = Courses.CourseId
inner join Student on Enrollments.StudentId = Student.Id
where Courses.CourseId = 1
or better with aliases for the tables:
select *
from Courses as c
inner join Enrollments as e on e.CourseId = c.CourseId
inner join Student as s on e.StudentId = s.Id
where c.CourseId = 1
The primary key of table Student is Id, not StudentId.
So the correct query is:
select * from Courses
inner join Enrollments on Enrollments.CourseId = Courses.CourseId
inner join Student on Enrollments.StudentId = Student.Id
where Courses.CourseId = 1

How to make a query from 4 tables

I am having a problem creating a View using SQL. I need to make a View of 4 tables:
tbl_school, tbl_teacher, tb_student, and tbl_class.
This is my table structure:
And this is my View Statement
SELECT
tbl_school.school_id,
tbl_school.school_nm,
(SELECT COUNT(*) FROM tbl_class) AS class,
(SELECT COUNT(*) FROM tbl_teacher) AS teacher,
(SELECT COUNT(*) FROM tbl_student) AS student
FROM
tbl_school
INNER JOIN tbl_teacher ON tbl_school.school_id = tbl_teacher.school_id
INNER JOIN tbl_class ON tbl_teacher.teacher_id = tbl_class.teacher_id AND tbl_school.school_id = tbl_class.school_id
INNER JOIN tbl_student ON tbl_class.class_id = tbl_student.class_id
GROUP BY
tbl_school.school_id
And this is the query result:
The problem is that I have one teacher in SD1 School and another teacher in SD2 School. Each teacher has one class and SD1 School has two students and SD2 School has one student.
Is there a way I can get the results that I desire?
You can use an aggregation containing DISTINCT keywords, and had better using aliasing and one more column (tbl_school.school_nm) within the GROUP BY list to make it a more proper SQL( Btw some DBMS don't allow excluding that column from GROUP BY while MySQL allows ) :
SELECT s.school_id, s.school_nm,
COUNT(DISTINCT c.class_id) AS class,
COUNT(DISTINCT t.teacher_id) AS teacher,
COUNT(DISTINCT d.student_id) AS student -- this is a presumedly existing column within the student table
FROM tbl_school s
JOIN tbl_teacher t ON s.school_id = t.school_id
JOIN tbl_class c ON t.teacher_id = c.teacher_id AND s.school_id = c.school_id
JOIN tbl_student d ON c.class_id = d.class_id
GROUP BY s.school_id, s.school_nm
Welcome to SO.
It has been a while since I have done this, but have you tried adding a WHERE modifier to your internal SQL select statements? Like this...
Side note: It makes more sense, to me, to also have a FK on tbl_student that links them to which school that they're in.
SELECT
tbl_school.school_id,
tbl_school.school_nm,
(SELECT COUNT(*) FROM tbl_class WHERE school_id=tbl_school.school_id) AS class,
(SELECT COUNT(*) FROM tbl_teacher WHERE school_id=tbl_school.school_id) AS teacher,
(SELECT COUNT(*) FROM tbl_student) AS student
FROM
tbl_school
INNER JOIN tbl_teacher ON tbl_school.school_id = tbl_teacher.school_id
INNER JOIN tbl_class ON tbl_teacher.teacher_id = tbl_class.teacher_id AND tbl_school.school_id = tbl_class.school_id
INNER JOIN tbl_student ON tbl_class.class_id = tbl_student.class_id
GROUP BY
tbl_school.school_id

SQL: Need to check columns for values that exist in another column

Using SQL, my job is to fetch the SSN of students who enrolled in a course without enrolling in that course’s prerequisite(s). I'm using Access. The tables I need are as follows:
STUDENT (SSN, SNAME, MAJOR, DOB, ADDRESS)
ENROLLED (SSN, CID, GRADE)
PREQ (CID, PREQCID, PASSINGGRADE, NOTE)
Here's what I've done so far.
select *
from
(select SSN, CID from ENROLLED) AS enrolled
left join
(select CID, PREQCID FROM PREQ) AS prereq ON enrolled.CID = prereq.CID;
What I'm missing is how to check each row of the same student on the condition WHERE enrolled.CID = prereq.CID for a PREQCID that's NOT in enrolled.CID.
Is what I'm asking for here a loop? Am I on the right track? Please keep in mind this I'm in an introductory course so the simplest of solutions is preferable.
Here's another way using not exists:
select e1.ssn
from enrolled e1 left join preq p on e1.cid = p.cid
where
p.preqcid is not null and
not exists (select 1 from enrolled e2 where e2.ssn = e1.ssn and e2.cid = p.preqcid)
This is essentially stating:
"Select the ssn for all enrollments where there is a prerequisite course and the prerequisite course ID does not exist in the table of enrollments for that ssn."
I use select 1 purely for optimisation - we don't care about the values held by the nested query, only whether or not the nested query returns one or more records.
You could also write this using joins as:
select e1.ssn
from
(
enrolled e1 left join preq p on e1.cid = p.cid
)
left join enrolled e2 on
p.preqcid = e2.cid and e1.ssn = e2.ssn
where
e2.cid is null
Here, the enrolled table is referenced twice: the first is left joined on the table of prerequisite courses for each course, and the second is left joined on the prerequisite course ID and the ssn from the original enrollment.
The where clause then causes records to be selected for which the link on the prerequisite course is null for the given ssn.
I'm sure there is a cleaner way to do this, but this gets you your result:
Select S.SSN, E.CID From Student S
Inner Join Enrolled E on E.SSN = S.SSN
Where E.CID IN (Select CID From PREQ Where Preqcid NOT IN
(Select CID From Enbrolled Where SSN = S.SSN))
This might work if analytic functions and CTEs are available:
with d as (
select ssn, cid,
count(distinct p.cid) over (partition by e.ssn, e.cid) ecnt, ,
count(distinct e.cid) over (partition by e.ssn, p.cid) pcnt
from enrolled e left outer join preq p on p.cid = e.cid
)
select distinct ssn, cid from d
where ecnt = pcnt;

Selecting SQL data based on multiple separate tables

I'm doing some SQL practice and have been stumped by the following question.
I'm given the database schema:
Course (Course#, title, dept)
Student (Student#, name, program)
Enrolled (Student#, Course#, grade)
I'm trying the translate the following statement to SQL:
List the names of all students who takes Computer courses or Science courses.
Initially I thought the answer might be something like this:
SELECT Sname
FROM Course,Student,Enrolled
WHERE Course.dept = "Computer" OR Course.dept = "Science"
However, I feel like the rows in the table are not joined quite how I imagined, and that there is something off with this. How far off am I?
This is not that simple: first, you need to join the tables, and then you need to group by name to eliminate duplicates:
SELECT s.name
FROM Student s
JOIN Enrolled e ON s.Student#=e.Student#
JOIN Course c ON e.Course#=c.Course#
WHERE c.dept = 'Computer' OR c.dept = 'Science'
GROUP BY s.name
GROUP BY is necessary because the same student may be taking both "Computer" and "Science" courses, in which case JOIN would produce multiple records for the same student. In this case you have an option of replacing it with DISTINCT.
If you have 2 courses Computing (1) and Science (2) with the IDs 1 and 2, you need to do a query like this:
SELECT s.first_name, s.last_name FROM students s JOIN enrolled e ON e.student_id = s.id WHERE e.course_id IN(1, 2)
Sorry may have misread, if you need to do it by course type and the courses are tagged as dept = Computer, Science, Literacy etc... Do the following query:
SELECT s.first_name, s.last_name FROM students s JOIN enrolled e ON e.student_id = s.id JOIN courses c ON c.id = e.course_id WHERE c.dept IN('Computing', 'Science')
Or if you want to do an OR:
SELECT s.first_name, s.last_name FROM students s JOIN enrolled e ON e.student_id = s.id JOIN courses c ON c.id = e.course_id WHERE c.dept = 'Computing' OR c.dept = 'Science'

sql self join problems how to find the duplicates from same table

I am student and
I have such kind of a table structures
student (sid, sname, gender, age, year, gpa)
dept(dname, numphds)
course(cno, cname, dname)
enroll(sid, grade, dname, cno, sectno)
and i want the results for.....
Q-Print the names of students who are taking both a "Computer Sciences" course and a "Maths" course................
I have tried following query but it does not give me throughput..............
select e.sid, s.sname from
enroll e ,enroll e1 ,student s ,course c
where s.sid=e.sid,
e.cno =c.cno
and e.sid=e1.sid
and c.cname='computer science' and c.name='maths';
It's been more than 20 years since proper joins were introduced to SQL. FFS use them!
Try this:
select s.sid, s.sname
from student s
join enroll e on e.sid = s.sid
join course c on c.cno = e.cno and c.cname='computer science'
join enroll e1 on e1.sid = s.sid
join course c1 on c1.cno = e1.cno and c1.name='maths'
Note how you may put non-key conditions in a join condition. Although the query would still work if the course names were in a where clause, putting the conditions in the join clause makes it more obvious where they apply, which improves readability.
By formatting well and ordering the tables sanely, you can actually read the query and (hopefully) understand it.
use the following code
select e.said, s.sname from enroll e inner join
enrool e1 on e1.sid = e.sid inner join
student s on s.sid = e.sid inner join
course c on c.cno = e.cno
where c.cname = 'computer science' and c.name = 'maths'
if you need to use the left join then use
select e.said, s.sname from enroll e left join
enrool e1 on e1.sid = e.sid left join
student s on s.sid = e.sid left join
course c on c.cno = e.cno
where c.cname = 'computer science' and c.name = 'maths'