SQL- Referencing the primary key of the current relation (homework) - sql

I'm working on a DB system for a university holding teachers, courses, students, and so on. In my student relation I'd like to include an attribute name Mentor the value of which would be student(SID). What is the best way to go about this?

If I'm reading your question correctly the Mentor would be another student so you'd have a self-referencing foreign key. That is, the foreign key on Mentor would reference the same table that contains the Mentor (i.e. Student).
You don't say which RDBMS you're using so the following is pseudocode rather than the actual SQL for any particular database.
create table Student
StudentId int primary key
MendtorId int foreign key references Student.StudentId

Related

When will it be considered an OVERKILL when making a composite primary key?

Recently, I stumbled upon this question when looking through my database notes.
In the case of an annual examination (A Levels, O Levels) where students who did not attain their desired marks are allowed for a re-sit in the following years,
suppose there was a database designed for the school to track that has the following attributes
Student ID, Exam module, Exam Date, Exam Results
Question provided by the book (not my personal question): what would be some appropriate primary keys?[5]
Now, I know that several primary key should not be used:
Purely Student ID
(Student ID + Exam Module)
And I also know that perhaps
Artificial Primary Key - extending a 5th column that auto-increments
(Student ID + Exam Module + Exam Date)
could be used as a primary key
My question comes from making a composite primary key from all attributes (Student ID + Exam Module + Exam Date + Exam Results). A part of me thinks it will work as a composite primary key but it does not make sense to provide every single table with a composite primary key consisting of all columns.
From your description of the question, the following tuple of columns should be unique throughout the table: (StudentID, ExamModule, ExamDate), because a student may take the same exam on different dates (actually: different years). The result of the exam should not be part of this unique column tuple: this prevents a student to two results for the same exam.
Whether you decide to make this tuple of columns the primary key of your table or use some kind of serial column as primary key is mostly a matter of taste. If you go for a serial key, you need to put a composite unique constraint on the three above columns anyway.
This is not necessarily along the line of the OP's initial question:
Question: what would be some appropriate primary keys?
but..(in hind site) I would have an IDENTITY field as a primary key.
And have the StudentID as just an Index (non unique) and as an alternate Key.

Query regarding SQLite and Cascading foreign keys

I am currently writing a application in C# that uses a SQLite database to store information the user will input. The application is basically a Management system for users who are called "Students" in the application. This is the most important table in my database and every other table is linked off this table. What I want to do is when a student is removed - they leave the institute/get kicked out etc. - is to remove their data from all the other tables so that data is no longer there as it isn't needed. An example of some of the Create table statements I have written is:
CREATE TABLE student(studentID int(5) PRIMARY KEY NOT NULL, name string(16),...,DOB string(8) );
CREATE TABLE emergencyContact(emergencyID int(5) PRIMARY KEY NOT NULL, name string(16),..., contactNumber int(16));
CREATE TABLE emergencyContactOf(studentID int(5) FOREIGN KEY REFERENCES student('studentID'), emergencyID int(5) FOREIGN KEY REFERENCES emergencyContact('emergencyID');
I have read up on this and my understanding is the data will be deleted in the EmergencyContactOf table if I include a 'ON DELETE CASCADE' statement as the StudentID key will no longer be present in the Parent table.
However, my understanding is the data in the EmergencyContact table that is for that specific student will not be deleted as there is no reference to the StudentID.
My question is, is there a way to remove the data from this table also that is relevant to that Student? For example, if I was to include a column in the EmergencyContact table which would reference the StudentID as a Foreign Key and then remove that row if the StudentID is ever deleted from the parent table? Is this a good solution to this particular problem?
All other tables I have are also designed in this way, where the data is in different tables and then linked back to the Student table with relationship tables so this will also apply to all the other tables I have.
Thanks.
My question is, is there a way to remove the data from this table also that is relevant to that Student? For example, if I was to include a column in the EmergencyContact table which would reference the StudentID as a Foreign Key and then remove that row if the StudentID is ever deleted from the parent table? Is this a good solution to this particular problem?
What happens if multiple students have the same emergency contact? You don't want to duplicate data if you don't have to - that's the whole point of the emergencyContactOf table, to efficiently set up a many to many relation between students and emergency contacts. So you don't want to do something like you describe.
You could periodically (Monthly, yearly, after purging student rosters, whatever) run a delete that removes rows from emergencyContact if they don't appear in emergencyContactOf:
DELETE FROM emergencyContact
WHERE emergencyID NOT IN (SELECT emergencyID FROM emergencyContactOf)
or the like.
Hmm, I see two scenarios here. What if two students have the same emergency contact, say two bothers having their father as emergency contact?
If in such a case you store only one record (the father) in the emergency contact table, you don't want to delete the emergency contact if only one of them leaves. You'd delete the emergency contact for the other one. So you'd need additional logic, when to delete an emergency contact. You could put that in a trigger.
You use a less sophisticated approach and multiple rows from the emergency contact table can map to one person in real life. In that case you can pull the reference to the student directly into the emergency contact table and use ON DELETE CASCADE there.
CREATE TABLE student
(studentid int(5),
name string(16),
...
PRIMARY KEY (studentid),
...);
...
CREATE TABLE emergencycontact
(emergencycontactid int(5),
studentid int(5),
name string(16),
...
PRIMARY KEY (emergencycontactid),
FOREIGN KEY (studentid)
REFERENCES student
(studentid),
...);
The second might be tempting but the "clean way" is the first one, as the second allows contradicting data. From what you posted you're already on the "clean way". But a mentioned that required triggers.

ER Diagram Participation Constraints in SQL

I'm trying to understand converting ER diagrams into SQL CREATE statements, but I am having a hard time with understanding how participation constraints work. In an ER diagram a participation constrain is represented by a bold line which means that every tuple in the table must appear in the relationship table. If there is a participation constraint and a key constraint (total) it is possible to fulfil the key constrain.
Is there ever a situation in which there is a way to enforce a participation constraint that isn't also a key constraint without using assertions or check constraints?
Edit
I was more confused about the whole concept as opposed to one particular example, but I was able to find an example that I drew out the diagram for that would illustrate my confusion. In the picture below we have a participation constraint and a key constraint from professors to teachers; therefore every professor must teach 1 class and only 1 class. This constraint can be enforced by having a professors_teach table as opposed to having two separate tables; by making the professors ssn the primary key there will only ever be 1 entry for each professor in the professors_teach table, and since it will have all the records that normally would be put in the professors table then every professor must be in the new table.
My confusion is in the participation constraint from course to teacher; basically what the diagram is saying is that every course must have at least one teacher; which I don't think can be enforced without using assertions or check constraints.
For this case you dont need a relatioship.
You only need table teacher, and define the field course_id (unique). In this case you have teachers and they can have 0 or 1 course. And each course will be teach for only one teacher.
teacher_id (primary key)
teacher_name
ssn
course_id (unique) fk reference courses(course_id)
Courses
course_id (primary key)
course_name
But you shouldnt enforce every course have teacher in the db because a new course will need a teacher right away. Is better you insert the course and then assign a teacher.
You merge the relation Teaches and the Entity Professor in:
CREATE TABLE Prof_teaches(
ssn INTEGER,
semesterid INTEGER,
courseID INTEGER NOT NULL,
FOREIGN KEY courseID REFERENCES Course (courseid),
PRIMARY KEY ssn
)
CREATE TABLE Course(
courseid INTEGER PRIMARY KEY
)
This is for total participation and key constraint as defined in the Book by Ramakrishnan. Meaning that each Professor (note, single f), participates in al least (total participation) and at most (key constraint) one teaches relationship.

Create table with two references in a foreign key

CREATE TABLE Album (
name VARCHAR(50),
lenght FLOAT,
genre VARCHAR(30),
nrSongs INT,
PRIMARY KEY (name, writer),
FOREIGN KEY (writer) REFERENCES Musician(name) OR Band(name),
FOREIGN KEY (Studio) REFERENCES Studio(name)
);
Ok this is what I'm trying to do, I have two tables called Musician and Band, and in the foreign key called writer I want to use the name of a Musician or a Band, but this gives me an error in the OR statement, do you know the correct way to implement this? I can't find it.
Thanks :)
Not possible. A foreign key is a direct link between one field in one table, and another field in another table. It is 1:1. You cannot have n:1, 1:n, or n:n mappings in a foreign key definition.
Plus, your overall table definition is invalid. You have no writer field, so your primary key and the writer FK will fail anyways.
For this particular purpose, why not just making everyone a "band". A solo artist is simply a band that happens to have one member.

What is the necessity of junction tables?

I have implemented the following ways of storing relational topology:
1.A general junction relation table:
Table: Relation
Columns: id parent_type parent_id parent_prop child_type child_id child_prop
On which joins are not generally capable of being executed against by most sql engines.
2.Relation specific junction tables
Table: Class2Student
Columns: id parent_id parent_prop child_id child_prop
On which joins are capable of being executed against.
3.Storing lists/string maps of related objects in a text field on both bidirectional objects.
Class: Class
Class properties: id name students
Table columns: id name students_keys
Rows: 1 "history" [{type:Basic_student,id:1},{type:Advanced_student,id:3}]
To enable joins by the sql engines, it would be possible to write a custom module which would be made even easier if the contents of students_keys was simply [1,3], ie that a relation was to the explicit Student type.
The questions are the following in the context of:
I fail to see what the point of a junction table is. For example, I fail to see that any problems the following arguments for a junction table claim to relieve, actually exist:
Inability to logically correctly save a bidirectional relations (eg
there is no data orphaning in bidirectional relations or any
relations with a keys field, because one recursively saves and one can enforce
other operations (delete,update) quite easily)
Inability to join effectively
I am not soliciting opinions on your personal opinions on best practices or any cult-like statements on normalization.
The explicit question(s) are the following:
What are the instances where one would want to query a junction table that is not provided by querying a owning object's keys field?
What are logical implementation problems in the context of computation provided by the sql engine where the junction table is preferable?
The only implementation difference with regards to a junction table vs a keys fields is the following:
When searching for a query of the following nature you would need to match against the keys field with either a custom indexing implementation or some other reasonable implementation:
class_dao.search({students:advanced_student_3,name:"history"});
search for Classes that have a particular student and name "history"
As opposed to searching the indexed columns of the junction table and then selecting the approriate Classes.
I have been unable to identify answers why a junction table is logically preferable for quite literally any reason. I am not claiming this is the case or do I have a religious preference one way or another as evidenced by the fact that I implemented multiple ways of achieving this. My problem is I do not know what they are.
The way I see it, you have have several entities
CREATE TABLE StudentType
(
Id Int PRIMARY KEY,
Name NVarChar(50)
);
INSERT StudentType VALUES
(
(1, 'Basic'),
(2, 'Advanced'),
(3, 'SomeOtherCategory')
);
CREATE TABLE Student
(
Id Int PRIMARY KEY,
Name NVarChar(200),
OtherAttributeCommonToAllStudents Int,
Type Int,
CONSTRAINT FK_Student_StudentType
FOREIGN KEY (Type) REFERENCES StudentType(Id)
)
CREATE TABLE StudentAdvanced
(
Id Int PRIMARY KEY,
AdvancedOnlyAttribute Int,
CONSTRIANT FK_StudentAdvanced_Student
FOREIGN KEY (Id) REFERENCES Student(Id)
)
CREATE TABLE StudentSomeOtherCategory
(
Id Int PRIMARY KEY,
SomeOtherCategoryOnlyAttribute Int,
CONSTRIANT FK_StudentSomeOtherCategory_Student
FOREIGN KEY (Id) REFERENCES Student(Id)
)
Any attributes that are common to all students have columns on the Student table.
Types of student that have extra attributes are added to the StudentType table.
Each extra student type gets a Student<TypeName> table to store its specific attributes. These tables have an optional one-to-one relationship with Student.
I think that your "straw-man" junction table is a partial implementation of an EAV anti-pattern, the only time this is sensible, is when you can't know what attributes you need to model, i.e. your data will be entirely unstructured. When this is a real requirment, relational databases start to look less desirable. On those occasions consider a NOSQL/Document database alternative.
A junction table would be useful in the following scenario.
Say we add a Class entity to the model.
CREATE TABLE Class
(
Id Int PRIMARY KEY,
...
)
Its concievable that we would like to store the many-to-many realtionship between students and classes.
CREATE TABLE Registration
(
Id Int PRIMARY KEY,
StudentId Int,
ClassId Int,
CONSTRAINT FK_Registration_Student
FOREIGN KEY (StudentId) REFERENCES Student(Id),
CONSTRAINT FK_Registration_Class
FOREIGN KEY (ClassId) REFERENCES Class(Id)
)
This entity would be the right place to store attributes that relate specifically to a student's registration to a class, perhaps a completion flag for instance. Other data would naturally relate to this junction, pehaps a class specific attendance record or a grade history.
If you don't relate Class and Student in this way, how would you select both, all the students in a class, and all the classes a student reads. Performance wise, this is easily optimised by indices on key columns.
When a many-to-many realtionships exists without any attributes I agree that logically, the junction table needn't exist. However, in a relational database, junction tables are still a useful physical implmentaion, perhaps like this,
CREATE TABLE StudentClass
(
StudentId Int,
ClassId Int,
CONSTRAINT PK_StudentClass PRIMARY KEY (ClassId, StudentId),
CONSTRAINT FK_Registration_Student
FOREIGN KEY (StudentId) REFERENCES Student(Id),
CONSTRAINT FK_Registration_Class
FOREIGN KEY (ClassId) REFERENCES Class(Id)
)
this allows simple queries like
// students in a class?
SELECT StudentId
FROM StudentClass
WHERE ClassId = #classId
// classes read by a student?
SELECT ClassId
FROM StudentClass
WHERE StudentId = #studentId
additionaly, this enables a simple way to manage the relationship, partially or completely from either aspect, that will be familar to relational database developers and sargeable by query optimisers.