Using constraint in table of teacher and students - sql

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
);

Related

SQL select - Get all from exams table where examId exists in subjects table, for all subjects that exist in students table for desired studentId

I have three tables: exams, subjects and students.
Students table has foreign key subjectId and Subjects table has foreign key examId.
I need to retrieve all exams for desired studentId. So I need sql select that will pick up all subjects for that studentId, and pick up all exams for all these subjects.
So pseudo code is something like:
SELECT * FROM exams
WHERE id IN (SELECT examId FROM subjects
WHERE id IN (SELECT subjectId from students
where id === desiredId))
Why are you using subqueries and just not inner join?
Try with this:
Select X.* From exams X
Inner join subjects S on S.examId = X.id
Inner join students T on T.subjectId = s.Id
Where T.id =#yourStudentId

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).

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

select sections which do not have any students enrolled

I want to select all sections which do not have any students enrolled
These are the three tables:
ENROLLMENTS
student_id, section_id
SECTIONS
course_id, section_id
COURSES
course_id, description
The output table should look like this:
course_id | description | section_id
I'm not shure which join to use.
So you want
SELECT
course_id
, description
, section_id
FROM
COURSES
INNER JOIN
SECTIONS
ON
COURSES.course_id = SECTIONS.course_id
LEFT JOIN
ENROLLMENTS
ON
ENROLLMENTS.section_id = SECTIONS.section_id
WHERE
ENROLLMENTS.student_id IS NULL;
This will take all of the information from COURSES and SECTIONS, then join it to ENROLLMENTS, keeping all of the information for COURSES and SECTIONS where there an no enrollments. Then by selecting where the ENROLLMENTS student_id is NULL we find all the entries that didn't have section_ids in SECTIONS.
Why not using a subquery?
SELECT
sections.course_id,
courses.description,
sections.section_id
FROM
courses INNER JOIN sections ON courses.course_id = sections.course_id
WHERE
courses.section_id NOT IN (SELECT section_id FROM enrollments)

SQL to select a table through a generic relationship

In a relational database I have three tables. Using SQL Server.
person(id, type)
student(id, person_id, type, student specific fields)
teacher(id, person_id, type, teacher specific fields)
Student and teacher are both people, therefore a student will have a record in both the person and student tables, as will the teacher. Student and teacher have foreign keys to person. Student and teacher have different field definitions therefore a union will NOT work.
Now I have the person's id and depending on whether the person is a student or teacher I would like to select * from the relevant table (not person).
For example, if the person is a student I would like my query to select the student table.
I can think of a few inefficient methods but I am looking for the optimum one.
I would suggest a UNION
SELECT student.*
FROM student
WHERE person_id= #id
UNION
SELECT teacher.*
FROM teacher
WHERE person_id= #id
if exists(select person_id from student where person_id = #id)
select * from student where person_id = #id
else
if exists(select person_id from teacher where person_id = #id)
select * from teacher where person_id = #id
If your RDBMS is SQLServer, then I would abstract a view along the lines of podiluska's union, mapping out specific fields in Student and Teacher to common names, and padding with NULLs where no mapping is possible
And assuming that Students and Teachers inherit from person (i.e. both are 0..1 to 1 with Person), then they can share the same primary key, i.e. no need for new surrogates keys on Teacher and Student.
I've assumed that person.type determines whether the person is a Student(S) or Teacher(T).
CREATE VIEW SubClassesOfPerson AS
SELECT p.id as PersonId,
p.name as PersonName,
p.OtherBaseFieldsHere,
s.SomeStudentSpecificField AS MappedField1,
s.SomeStudentSpecificFieldX AS MappedFieldX,
s.SomeStudentSpecificField as MappedFieldForStudentOnly,
NULL as MappedFieldForTeacherOnly -- Pad this because it can't be mapped
FROM person p
INNER JOIN student s
on s.person_id = p.id AND p.type = 'S'
UNION
SELECT p.id as PersonId,
p.name as PersonName,
p.OtherBaseFieldsHere,
t.SomeTeacherSpecificField AS MappedField1,
t.SomeTeacherSpecificFieldX AS MappedFieldX,
NULL as MappedFieldForStudentOnly, -- Pad this because it can't be mapped
t.SomeTeacherSpecificField as MappedFieldForTeacherOnly
FROM person p
INNER JOIN teacher t
on t.person_id = p.id AND p.type = 'T'