How to write SQL Subquery queries - sql

I have a database which has 5 table
COURSES (CourseID, CourseName, Credit) // CourseID is primary key
TEACHERS (SSN, Name) // SSN is primary key
OFFER (CourseID, SSN) // CourseID and SSN are foreign key
STUDENTS (StudentID, Name, Department) // StudentID is primary key
ENROLL (StudentID, CourseID, Semester)
And i want to find the names of the students who enroll to courses that are enrolled by student whose name is “Jack Lion”.
I tried the below statements but i can't figure out how to solve.
SELECT STUDENTS.Name from STUDENTS
WHERE STUDENTS.StudentID IN (SELECT ENROLL.StudentID from ENROLL
-- I don't know what to write here
)
I just got this far can u help me or at least give me some examples that would help me to solve this. I use Microsoft sql server by the way.

Nest your subqueries
SELECT STUDENTS.Name from STUDENTS
WHERE STUDENTS.StudentID IN (SELECT ENROLL.StudentID
from ENROLL
WHERE CourseID IN (SELECT CourseID
FROM ENROLL
WHERE StudentID IN (SELECT StudentID
FROM STUDENTS
WHERE Name = 'Jack Lion'
)
)
)

Related

SQL statement is returning the top value rather than the correct value

I have these tables with practice questions that are asked, but I am running into some issues. The first question asks "Find the first name and last name of the student who has the highest GPA in CIS415 in Fall 2019."
The tables that are needed to find the correct values:
Students (SID, Firstname, Lastname, Age, Email, Phone) //SID = Student ID
Courses (CID, Name, Capacity) //CID = Course ID
Enrolls (CID, SID, Semester, GPA)
The SQL statement I have currently is:
SELECT Firstname, Lastname
FROM students
JOIN Enrolls ON student.sid = enrolls.sid
GROUP BY CID, Semester
HAVING MAX(GPA)
AND CID = 'CIS415'
AND semester = 'Fall2019';
I believe it is just pulling the students firstname and lastname from the top of the table. I am unsure of the problem and would love some input. THANK YOU.
SELECT [S].[Firstname], [S].[Lastname]
FROM Students [S]
INNER JOIN Enrolls [E]
ON [S].[SID] = [E].[SID]
INNER JOIN
(
SELECT MAX( [GPA] ) AS [GPA],
[CID] AS [CID],
[SID] AS [SID]
FROM Enrolls [E2]
GROUP BY
[CID], [SID]
) [DT]
ON [E].[CID] = [DT].[CID]
AND [E].[SID] = [DT].[SID]
WHERE
[E].[CID] = 'CIS415'
AND
[E].[semester] = 'Fall2019'
AND
[E].[GPA] >= [DT].[GPA]

SQL Find all courses who have more students enrolled then the allowed enroll_limit for the course

I'm currently taking a database class and I am stuck on a homework problem due tonight
Find the courses given in the ‘Sloan’ building which have enrolled more students than their enrollment limit. Return the courseno, enroll_limit, and the actual enrollment for those courses.
I'm stuck trying to count how many students are in each course.
CREATE TABLE Course (
courseno VARCHAR(7),
credits INTEGER NOT NULL,
enroll_limit INTEGER,
classroom VARCHAR(10),
PRIMARY KEY(courseNo), );
CREATE TABLE Student (
sID CHAR(8),
sName VARCHAR(30),
major VARCHAR(10),
trackcode VARCHAR(10),
PRIMARY KEY(sID),
FOREIGN KEY (major,trackcode) REFERENCES Tracks(major,trackcode) );
CREATE TABLE Enroll (
courseno VARCHAR(7),
sID CHAR(8),
grade FLOAT NOT NULL,
PRIMARY KEY (courseNo, sID),
FOREIGN KEY (courseNo) REFERENCES Course(courseNo),
FOREIGN KEY (sID) REFERENCES Student(sID) );
My current very broken attempt is
SELECT sloancourse.courseno
FROM course sloancourse
WHERE
sloancourse.classroom = 'Sloan'
and sloancourse.courseno IN (
SELECT c.courseno
FROM student s, enroll e, course c
WHERE
c.courseno = e.courseno
and s.sid = e.sid
and sloancourse.courseno = c.courseno
)
;
Find the courses given in the ‘Sloan’ building which have enrolled more students than their enrollment limit. Return the courseno, enroll_limit, and the actual enrollment for those courses.
You would typically join courses and enrollment (using stanard join syntax, with the on keyword), group by course, and finally filter on courses whose student count with a having clause.
select
c.courseno,
c.enroll_limit,
count(*) actual_enrollment
from course c
inner join enroll e on e.courseno= c.courseno
where c.classroom = 'Sloan'
group by c.courseno, c.enroll_limit
having count(*) > c.enroll_limit
Note that you don't need to bring in the student table to get the desired results.
You could try something like this:
SELECT
Course.courseno,
Course.enroll_limit,
Couse.classroom
FROM Course, Enroll
WHERE Course.courseno = Enroll.courseno
AND Course.classroom = 'Sloan'
GROUP BY Course.courseno
HAVING count(*) > Course.enroll_limit
Postgres docs have an example on these aggregate functions: https://www.postgresql.org/docs/current/tutorial-agg.html
Basically, when you group by one or multiple properties, the resulting table will result in a unique row for the property/combination of properties. In this example, you would have one row for each of the courseno unique values (as they are grouped by this value).

Using constraint in table of teacher and students

For example, I have 3 tables: teachers, students and persons.
Teachers with teacher_id and person_id,
Students with student_id and person_id,
Persons with person_id and some information about him.
How should I use constraint to avoid situation, when the same person is teacher and student. I know how to use constraint in simple ways, like limiting dates or other integer values. But here I have no idea how to connect and constraint them.
If you want to SELECT all persons, but the students who are teachers, you can put that in your WHERE clause:
SELECT *
FROM persons p
INNER JOIN student_id s
ON s.person_id = p.person_id
INNER JOIN teacher_id t
ON t.person_id = p.person_id
WHERE student_id != teacher_id
Update
Use the WHERE clause in a CASE statement while creating your index:
CREATE UNIQUE INDEX index_person ON index_table(
CASE WHEN student_id != teacher_id
THEN person_id
ELSE NULL
END
);

Output student number that exists only on primary key but doesn't exist on foreign key

I have two tables
Student table
student number primary key
Grade table
student number foreign key
I want to display only students that exist in the student table but don't exist in the grade table
This way you can select all students that are not found (by their id) in the grade table.
SELECT *
FROM student
WHERE id NOT IN (SELECT student_id FROM grade)
Just to round out the answers I usually prefer using joins for things like this a simple left join and testing for null value will do the trick.
SELECT s.*
FROM
student s
LEFT JOIN grade g
WHERE
g.student_Id IS NULL

How to solve this unique SQL query?

I have the following tables:
Student(Sid,Sname) Primary key: {sid}
Course(cid,cname,duration,fee) Primary key:{cid}
Enrolled(sid,cid) Foreighn key: {sid,cid}
Query: Find the maximum fees paid by each student where a student can
enroll in different courses.
My attempt:
SELECT ssid, max(fee) as MAX_FEES from (Select sid as ssid, C.cid asccid,
fee from Course C,Enrolled E where C.cid = E.cid) group by
rollup(ssid,ccid,fee)
However, this doesn't gives the desired output appropriately. How to output only the Highest fees paid by each student?
try
SELECT max(c.fee) from course c, student s, enrolled e where s.sid=e.sid and e.cid=c.cid group by e.sid;
You didn't say if you also needed to list the students who are not enrolled in any course, so I'll provide one more solution:
CREATE TABLE student (
sid NUMBER PRIMARY KEY,
sname VARCHAR2(40)
);
CREATE TABLE course (
cid NUMBER PRIMARY KEY,
cname VARCHAR2(40),
duration NUMBER,
fee NUMBER
);
CREATE TABLE enrolled (
sid NUMBER,
cid NUMBER,
PRIMARY KEY (sid, cid),
FOREIGN KEY (sid) REFERENCES student (sid),
FOREIGN KEY (cid) REFERENCES course (cid)
);
INSERT INTO student (sid, sname) VALUES (1, 'John');
INSERT INTO student (sid, sname) VALUES (2, 'Peter');
INSERT INTO student (sid, sname) VALUES (3, 'Jake');
INSERT INTO course (cid, cname, duration, fee) VALUES (1, 'Math', 1, 1000);
INSERT INTO course (cid, cname, duration, fee) VALUES (2, 'Physics', 1, 1500);
INSERT INTO enrolled (sid, cid) VALUES (1, 1); -- John taking Math
INSERT INTO enrolled (sid, cid) VALUES (1, 2); -- John taking Physics
-- Peter being lazy
INSERT INTO enrolled (sid, cid) VALUES (3, 1); -- Jake taking Math
COMMIT;
-- not taking lazy (not taking any courses) students under account
SELECT s.sid, MAX(c.fee)
FROM student s
JOIN enrolled e ON (e.sid = s.sid)
JOIN course c ON (e.cid = c.cid)
GROUP BY s.sid
;
-- all students
SELECT s.sid, NVL(MAX(c.fee), 0)
FROM student s
LEFT JOIN enrolled e ON (e.sid = s.sid)
LEFT JOIN course c ON (e.cid = c.cid)
GROUP BY s.sid
;