Add logical constraint while designing tables - sql

I have a table like below:
Student:
StudentId FirstName LastName Grade
Course:
CourseId Name Desc
Offering
OfferNum CourseId ProfessorId
Student_Course_Mapping
OfferNum StudentId
I have a constraint which says that student can enrol only in 2
offering for 1 term and year.
For eg: Lets say student john has enrol in Java and Python for Winter
term(January - April) 2020 than he cannot enrol in other courses.
I don't have any front end or anything else to restrict this. I only have been told to work with the database and apply this constraint.
Right now we are entering data manually in this table using SSMS design view.
So is it possible to restrict someone entering such data?

This type of numeric constraint between two tables is not trivial to implement.
Here are four approaches.
(1) Create a table with one row per student, term, and year. Have two columns, one for each course. It is not possible to have more than two with this approach.
(2) Create a user-defined function that calculates the number of courses for a student in a given term and year. Then create a check constraint using this function.
(3) Create a with one per student, term, and year and a count of the courses for the term. Maintain this count using a trigger and place a check constraint on the value.
(4) Maintain all the logic in the "application". This would entail doing all inserts via a stored procedure and having the stored procedure validate the business logic.
In your case, I would probably opt for (2) as the last intrusive solution. If you already had a table with one row per student/term/year, I would suggest (3). It does involve a trigger (argggh!) but it also maintains useful information for other purposes.

Related

sql many to many relationship table design

I am learning sql now and practicing the scenarios to design the tables. I have a one scenario where I could not find proper suitable table structure.
The scenarios is as follows, I want to store depedencies user journey in sql. For example, in customer creation journey, we need to create valid sector, language and country codes in the system. Another example, to create a new account (bank account), we need to create the sector, language and country followed by customer.
So far, I could think of following table design, but I am sure this is not good as there is no primary key and not following the normalization standards.
journey
dependent
order
CUSTOMER
SECTOR
0
CUSTOMER
LANGUAGE
1
CUSTOMER
COUNTRY
2
ACCOUNT
CUSTOMER
0
I understand that this is many to many relationship as one journey can have many dependent and one dependent can be associated with multiple journeys. I need help to efficiently design the tables in sql, please can anyone help on this.
You need from the intermediate/join table that should look like this -
Table name - journey_dependent
Coll(Jurney_FK) Coll(Dependent_FK)
journey_id dependent_id
You can check more here - https://www.baeldung.com/jpa-many-to-many#1-modeling-a-many-to-many-relationship
If journey and dependent values are PK in origin tables, you have 2 FK. You can create a composite PK on that table with that 2 columns.
Maybe order need to be in dependent table. If not, there is information on that table : order. So this is not a pur relationship table. So you could optionally had a technical PK column (auto increment) on it.

Design a table to store different values for single entity?

I am designing a database where I have a doubt. My requirement is to store the subject score for each student. I can achieve in two ways like below.
student_id and each subject as column and store one record for each student.
student_id,subject_name,score as columns and store one record per subject.
I need help in understanding the pros and cons of each implementation type.
Or table for Students:
StudentID - primary key
StudentName
etc.
and one for Subjects:
SubjectID - primary key
SubjectName
etc.
and one for Scores:
SubjectID
StudentID
Score
etc. (might be you want date here)
PrimaryKey (SubjectID, StudentID, SemesterID?)
Think about the last table - it will combine student and subject details given a score for each entity but you may need to add some date here, or exam ID or something else as one student may have score for same subject during the years (for example on math).
I think you're going to need 3 tables:
students
subjects
scores
students and subjects are master tables. They're going to provide student_id and subject_id for scores table as composite key. Here's the relational database design.
The point of seperating them into 3 tables is to avoid data anomalies. There are 3 anomalies:
Insert anomaly
Delete anomaly
Update anomaly
To learn more about data anomalies: https://www.geeksforgeeks.org/anomalies-in-relational-model/

SQL database structure with two changing properties

Let's assume I am building the backend of a university management software.
I have a users table with the following columns:
id
name
birthday
last_english_grade
last_it_grade
profs table columns:
id
name
birthday
I'd like to have a third table with which I can determine all professors teaching a student.
So I'd like to assign multiple teachers to each student.
Those Professors may change any time.
New students may be added any time too.
What's the best way to achieve this?
The canonical way to do this would be to introduce a third junction table, which exists mainly to relate users to professors:
users_profs (
user_id,
prof_id,
PRIMARY KEY (user_id, prof_id)
)
The primary key of this junction table is the combination of a user and professor ID. Note that this table is fairly lean, and avoids the problem of repeating metadata for a given user or professor. Rather, user/professor information remains in your two original tables, and does not get repeated.

Why is this table not normalized?

I am taking a database course and I am studying table normalization.
Could anyone explain to me, why the second table in the first row on the right not normalized?
It is not normalized because
For a student who has signed for more than one course, the entries in the table will be:
23 Jake Smith CS101 B+
23 Jake Smith B102 C+
Clearly the data is being repeated(redundant data). It is leading to anomalies(insert, update, delete anomalies).
Ex:When you have to change the name of a Student say Jake Smith, you have to modify all of the rows,this is called an update anomalie.
Normalization is used to avoid these kind of anomalies and redundant data storage.
The table on the right hand side in the second row handles this situation in a better way, as it stores id, name and DOB in a separate table, the edits can be made easily using id attribute on a single row.
There are several normal forms like 1NF, 2NF, 3NF etc. Each normal form has some constraints associated with it. Each Higher form being stricter than the previous one.
I suppose it is table for students grades. It is not normalized because it contains students names directly, instead of references to students records.
It's better not to include student_name into this table, but store all students data in separate students table and reference it by student_id foreign key (something like first table in second row except the ids.).
It's not normalised because neither id nor student_name is the key (both have duplicates) so the key must be one of those (probably id) together with the course code. The other one (name) then doesn't depend on that key, but just on id.
The simple rule for 3NF is that every non-key column must depend on "the key, the whole key, and nothing but the key" - to which we all solemnly intone "so help me Codd"!
The higher normal forms deal with dependencies inside the parts of a key.
Because in your first right table you have twice values
23 - j.smith
that is repeated and do not adhere to Codd 1 normal form

Database Technology - postgresql

I am quite new to postgresql. Could any expert help me solve this problem please.
Consider the following PostgreSQL tables created for a university system recording which students take which modules:
CREATE TABLE module (id bigserial, name text);
CREATE TABLE student (id bigserial, name text);
CREATE TABLE takes (student_id bigint, module bigint);
Rewrite the SQL to include sensible primary keys.
CREATE TABLE module
(
m_id bigserial,
name text,
CONSTRAINT m_key PRIMARY KEY (m_id)
);
CREATE TABLE student
(
s_id bigserial,
name text
CONSTRAINT s_key PRIMARY KEY (s_id)
);
CREATE TABLE takes
(
student_id bigint,
module bigint,
CONSTRAINT t_key PRIMARY KEY (student_id)
);
Given this schema I have the following questions:
Write an SQL query to count how many students are taking DATABASE.
SELECT COUNT(name)
FROM student
WHERE module = 'DATABASE' AND student_id=s_id
Write an SQL query to show the student IDs and names (but nothing else) of all student taking DATABASE
SELECT s_id, name
FROM Student, take
WHERE module = 'DATABASE' AND student_id = s_id
Write an SQL query to show the student IDs and names (but nothing else) of all students not taking DATABASE.
SELECT s_id, name
FROM Student, take
WHERE student_id = s_id AND module != 'DATABASE'
Above are my answers. Please correct me if I am wrong and please comment the reason. Thank you for your expertise.
This looks like homework so I'm not going to give a detailed answer. A few hints:
I found one case where you used ยด quotes instead of ' apostrophes. This suggests you're writing SQL in something like Microsoft Word, which does so-called "smart quotes. Don't do that. Use a sensible text editor. If you're on Windows, Notepad++ is a popular choice. (Fixed it when reformatting the question, but wanted to mention it.)
Don't use the legacy non-ANSI join syntax JOIN table1, table2, table3 WHERE .... It's horrible to read and it's much easier to make mistakes with. You should never have been taught it in the first place. Also, qualify your columns - take.module not just module. Always write ANSI joins, e.g. in your example above:
FROM Student, take
WHERE module = 'DATABASE' AND student_id = s_id
becomes
FROM student
INNER JOIN take
ON take.module = 'DATABASE'
AND take.student_id = student.s_id;
(if the table names are long you can use aliases like FROM student s then s.s_id)
Query 3 is totally wrong. Imagine if take has two rows for a student, one where the student is taking database and one where they're taking cooking. Your query will still return a result for them, even though they're taking database. (It'd also return the same student ID multiple times, which you don't want). Think about subqueries. You will need to query the student table, using a NOT EXISTS (SELECT .... FROM take ...) to filter out students who are not taking database. The rest you get to figure out on your own.
Also, your schemas don't actually enforce the constraint that a student may only take DATABASE once at a time. Either add that, or consider in your queries the possibility that a student might be registered for DATABASE twice.