Database table design for college management system - sql

I'm a lion beginner. I'm developing a database for College Management System. For that I decided to create tables. First basically I designed two tables..
They are Student and Department.
create table dept_pro
(
dept_id numeric(1) primary key,
name char(20),
hod nvarchar(25),
location nvarchar(10)
);
create table student_pro
(
rollno char(10) primary key,
name nvarchar(25) not null,
dept_id numeric(1) not null foreign key references dbo.dept_pro(dept_id),
ac_year numeric(1) not null check( ac_year in (1,2,3,4)),
sem numeric(1) not null check ( sem in (1,2)),
mobile nvarchar(13),
addr nvarchar not null
);
I established a relation between them using a Foreign Key. Now I need to add another set of tables, one for attendance and the other for maintaining marks. There will be maximum of 6 subjects in a semester, and after each semester the subjects change. As the subjects change the corresponding subjects in the attendance table should also change. How can I change the subjects in the marks and attendance table after each semester? And also another important issue is each subject has 3 exams. I tried to create a user-defined type for this each subject having 3 columns exam1,exam2 and exam3(In oracle we create user defined type as a combination of one or more columns).
I'm now using SQL Server. SQL Server is not supporting user-defined datatypes as in Oracle like CREATE DATA..... AS OBJECT.This is further increasing complexity of marks table.
Now how can I solve above problem of maintaining marks & attendance table keeping in mind that the subjects change after each semester. Help me I'm a beginner.
Thanks in advance!!

Related

What is the best way to construct database tables for many to many relationship (with additional condition)?

Business problem: Suppose that we have a few medical centers and doctors, who work in these centers. Obviously, many doctors can work in one center. But also one doctor can work in many centers at the same time. And we have to store information about who is the head doctor of each medical center (each medical center can have only one head doctor and one doctor can be the head doctor in multiple centers).
Question: What is the best way to construct database tables to serve these business requirements?
I see two variants (described below) but if you see more, please, let me know.
Variant 1
In this variant, we store information about the head doctor in the join table jobs. I see two disadvantages here:
the column jobs.is_head will contain false in most cases and it looks strange (and looks like we store unnecessary information).
we need somehow to restrict adding two head doctors into one center.
create table doctors
(
id bigint not null
constraint doctors_pk
primary key,
name varchar not null
);
create table medical_centers
(
id bigint not null
constraint medical_centers_pk
primary key,
address varchar not null
);
create table jobs
(
medical_center_id bigint not null
constraint centers_fk
references medical_centers,
doctor_id bigint not null
constraint doctors_fk
references doctors,
is_head boolean not null,
constraint jobs_pk
primary key (doctor_id, medical_center_id)
);
Variant 2
In this variant, we store information about the head doctor in medical_centers table. Two disadvantages again:
we have two types of relationships between tables now: many to many and one to many (because one doctor can be the head doctor in multiple centers), which is a bit complicated, especially considering that I want to use this schema through ORM framework (JPA implementation).
we have to somehow restrict setting doctor as a head doctor if this doctor is not working in this center.
create table doctors
(
id bigint not null
constraint doctors_pk
primary key,
name varchar not null
);
create table medical_centers
(
id bigint not null
constraint medical_centers_pk
primary key,
address varchar not null,
head_doctor_id bigint
head_doctor_id_fk
references doctors
);
create table jobs
(
medical_center_id bigint not null
constraint centers_fk
references medical_centers,
doctor_id bigint not null
constraint doctors_fk
references doctors,
constraint jobs_pk
primary key (doctor_id, medical_center_id)
);
It is a trade - off, but operational complexity or some(?) storage. I think variation 1 looks good. If you want to change a little bit you can add another table called "med_cen_heads" with unique constraint on med_center_id column. Thus, we prevent adding a second doctor to same medical center. The hard part is checking if the head doctor works in the medical center or not before insert.
INSERT INTO med_cen_heads
SELECT medical_center_id, doctor_id
FROM jobs
WHERE EXISTS (SELECT 1 FROM jobs WHERE medical_center_id = 'medical_center_id_to_insert' and doctor_id 'doctor_id_to_insert');
Also, you can create "before insert trigger" to check if values exist in jobs table.
It could look like this:
create table doctors
(
id bigint not null
constraint doctors_pk
primary key,
name varchar not null
);
create table medical_centers
(
id bigint not null
constraint medical_centers_pk
primary key,
address varchar not null
);
create table jobs
(
job_id serial,
medical_center_id bigint not null
constraint centers_fk
references medical_centers,
doctor_id bigint not null
constraint doctors_fk
references doctors
);
create table med_cen_heads
(
medical_center_id bigint unique not null,
doctor_id bigint not null
);
This will save you from unnecessary storage but, BOOLEAN data type is just 1 byte. Let' s assume you have 1 billion med_center - doctor pairs(I don' t think you will have). In this way you only store 0.93132 GB more for your extra column. Of course, becuse there is only one head doctor in a medical center this column will be skewed. Yet when you query normal doctors this column will not be your concern, you should use "doctor_id" or any other columns.
In short, from my point of view stick with variation 1 with this small change:
create unique index unique_row on jobs(medical_center_id) where is_head;
Check you cannot add a second head doctor to a medical center.

How to enforce a unique constraint across multiple tables?

I have created the following two tables to map out students and teachers :
CREATE TABLE students(
student_id SERIAL PRIMARY KEY,
first_name NOT NULL VARCHAR(50),
last_name NOT NULL VARCHAR(50),
phone VARCHAR(15) UNIQUE NOT NULL CHECK (phone NOT LIKE '%[^0-9]%'),
email VARCHAR(30) UNIQUE NOT NULL CHECK (email NOT LIKE '%#%'),
graduationYear SMALLINT CHECK (graduationYear > 1900)
);
CREATE TABLE teachers(
teacher_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
departament VARCHAR(40) NOT NULL,
email VARCHAR(30) UNIQUE NOT NULL CHECK (email NOT LIKE '%#%'),
phone VARCHAR(15) UNIQUE NOT NULL CHECK (phone NOT LIKE '%[^0-9]%')
);
As you can see, both tables have a column for phone and email. I want these two to be unique to each individual.
How can I introduce a constraint that will check if the phone number/email introduced, for example, in the students table doesn't already exist in the teachers table?
Is there any kind of keyword that works like UNIQUE but on multiple tables or should I take another approach?
Edit: as #a_horse_with_no_name pointed out, LIKE doesn't support regular expressions. I should have used SIMILAR TO.
I would create a single table person that contains all attributes that are common to both including a type column that identifies teachers and students. Then you can create unique constraints (or indexes) on the phone and email columns.
To store the "type specific" attributes (graduation year, department) you can either have nullable columns in the person table and only put in values depending on the type. If you do not expect to have more "type specific" attributes apart from those two, this is probably the easiest solution
If you expect more "type specific" attributes, additional tables (student and teacher) with containing those can also be used. This is the traditional way of modelling inheritance in a relational database. As Postgres supports table inheritance, you could also create the teacher and student tables to inherit from the person table.

How do I insert values for a column that has multiple values?

In a university database, I have a self referencing relationship for a subject and a pre-requisite.
Meaning that a subject can have 0 or more pre-requisites.
So I declared it in a table for subjects
subject_code VARCHAR(7) NOT NULL CONSTRAINT subject_pk PRIMARY KEY,
subject_name VARCHAR(50) NOT NULL,
pre_requisite VARCHAR(7) NULL CONSTRAINT unit_pre_code FOREIGN KEY
REFERENCES subject(subject_code),
So I am just wondering if I am right heading this way or should there be another table that deals with pre-requisites.
If I am in the right track, how do I insert a data that has a pre-requisite for the subject?
for example
C++(C12345) subject is a prerequisite to Operating Systems(C34512) or something.
I am still really new to this and I'm having a hard time looking for good and simple references for SQL. Any recommendations would be great too!
Your relationship is one to many i.e. 1 subject can have many prerequisites, you should therefore be using another table. e.g.
CREATE TABLE SubjectPrerequisite
( Primary_Subject_Code VARCHAR(7) NOT NULL,
Prerequisite_Subject_Code VARCHAR(7) NOT NULL,
CONSTRAINT PK_SubjectPrerequisite PRIMARY KEY (Primary_Subject_Code, Prerequisite_Subject_Code),
CONSTRAINT FK_SubjectPrerequisite_Primary_Subject_Code FOREIGN KEY (Primary_Subject_Code) REFERENCES Subject (Subject_Code),
CONSTRAINT FK_SubjectPrerequisite_Prerequisite_Subject_Code FOREIGN KEY (Prerequisite_Subject_Code) REFERENCES Subject (Subject_Code)
)
This will still maintain your referential integrity by having all the correct keys, but will make querying the database much easier where 1 subject has multiple prerequisites. e.g.
-- WILL RETURN ALL SUBJECTS AVAILABLE GIVEN A CERTAIN PERSONS
-- COMPLETED SUBJECTS.
SELECT DISTINCT s.*
FROM Subject s
INNER JOIN SubjectPrerequisite sp
ON s.Subject_Code = sp.Primary_Subject_Code
WHERE sp.Prerequisite_Subject_Code IN ('C12345', 'C12346')
-- WILL RETURN ALL PRERQUISITE SUBJECTS FOR ANY GIVEN SUBJECT
SELECT s.*
FROM SubjectPrerequisite sp
INNER JOIN Subject s
ON s.Subject_Code = sp.Prerequisite_Subject_Code
WHERE sp.Primary_Subject_Code = 'C34512'

How to design relation between tables employee,client and phone Number?

I have a relational database with a Client table, containing id, name, and address, with many phone numbers
and I have an Employee table, also containing id, name, address, etc., and also with many phone numbers.
Is it more logical to create one "Phone Number" table and link the Clients and Employees, or to create two separate "Phone Number" tables, one for Clients and one for Employees?
If I choose to create one table, can I use one foreign key for both the Client and Employee or do I have to make two foreign keys?
If I choose to make one foreign key, will I have to make the Client ids start at 1 and increment by 5, and Employee ids start at 2 and increment by 5 so the two ids will not be the same?
If I create two foreign keys will one have a value and the other allow nulls?
The solution which I would go with would be:
CREATE TABLE Employees (
employee_id INT NOT NULL,
first_name VARCHAR(30) NOT NULL,
...
CONSTRAINT PK_Employees PRIMARY KEY (employee_id)
)
CREATE TABLE Customers (
customer_id INT NOT NULL,
customer_name VARCHAR(50) NOT NULL,
...
CONSTRAINT PK_Customers PRIMARY KEY (customer_id)
)
-- This is basic, only supports U.S. numbers, and would need to be changed to
-- support international phone numbers
CREATE TABLE Phone_Numbers (
phone_number_id INT NOT NULL,
area_code CHAR(3) NOT NULL,
prefix CHAR(3) NOT NULL,
line_number CHAR(4) NOT NULL,
extension VARCHAR(10) NULL,
CONSTRAINT PK_Phone_Numbers PRIMARY KEY (phone_number_id),
CONSTRAINT UI_Phone_Numbers UNIQUE (area_code, prefix, line_number, extension)
)
CREATE TABLE Employee_Phone_Numbers (
employee_id INT NOT NULL,
phone_number_id INT NOT NULL,
CONSTRAINT PK_Employee_Phone_Numbers PRIMARY KEY (employee_id, phone_number_id)
)
CREATE TABLE Customer_Phone_Numbers (
customer_id INT NOT NULL,
phone_number_id INT NOT NULL,
CONSTRAINT PK_Customer_Phone_Numbers PRIMARY KEY (customer_id, phone_number_id)
)
Of course, the model might changed based on a lot of different things. Can an employee also be a customer? If two employees share a phone number how will you handle it on the front end when the phone number for one employee is changed? Will it change the number for the other employee as well? Warn the user and ask what they want to do?
Those last few questions don't necessarily affect how the data is ultimately modeled, but will certainly affect how the front-end is coded and what kind of stored procedures you might need to support it.
"The Right Way", allowing you to use foreign keys for everything, would be to have a fourth table phoneNumberOwner(id) and have fields client.phoneNumberOwnerId and employee.phoneNumberOwnerId; thus, each client and each employee has its own record in the phoneNumberOwner table. Then, your phoneNumbers table becomes (phoneNumberOwnerId, phoneNumber), allowing you to attach multiple phone numbers to each phoneNumberOwner record.
Maybe you can somehow justify it, but to my way of thinking it is not logical to have employees and clients in the same table. It seems you wan to do this only so that your foreign keys (in the telephone-number table) all point to the same table. This is not a good reason for combining employees and clients.
Use three tables: employees, clients, and telephone-number. In the telephone table, you can have a field that indicates employee or client. As an aside, I don't see why telephone number needs to be a foreign key: that only adds complexity with very little benefit, imo.
Unless there are special business requirements I would expect a telephone number to be an attribute of an employee or client entity and not an entity in its own right.
If it were considered an entity in its own right it would be 'all key' i.e. its identifier is the compound of its attributes and has no attributes other than its identifier. If the sub-attributes aren't stored apart then it only has one attribute i.e. the telephone number itself! Therefore, it isn't usually 'interesting' enough to be an entity in its own right and a telephone numbers table, whether superclass or subclass, is usually overkill (as I say, barring special business requirements).

Can a primary key contain more than one columns? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
is this possible to made two primary key in one table
Is it possible to define a primary key on more than one columne in MySQL?
How is this indicated in a create table statement?
Yes, you absolutely can.
Here's a link:
http://sqlzoo.net/howto/source/z.dir/tip241027/mysql
And here is the basic syntax:
CREATE TABLE myTable(
myCol1 INTEGER NOT NULL,
myCol2 CHAR(10) NOT NULL,
myCol3 INTEGER NOT NULL,
myCol4 CHAR(1),
PRIMARY KEY (myCol1 , myCol2 , myCol3 )
)
You can use:
CREATE TABLE tableName (
firstName varchar(10) NOT NULL,
surname varchar(20) NOT NULL,
primary key(firstName,surname)
);
I personally use this structure when I use a lookup table to connect many-to-many fields:
CREATE TABLE personPhoneNumbersLookup (
personID int(3) NOT NULL,
phoneNumberID int(4) NOT NULL,
primary key(personID,phoneNumberID)
);
To ensure that I only connect one particular person to one particular phone number once only. Though, obviously, the same personID can be used for other phone numbers, and multiple phone numbers can be connected to the same person.
Yes, it can
CREATE TABLE table1(col1 INT NOT NULL, col2 INT NOT NULL, PRIMARY KEY(col1,col2));
UPDATE
It's possible, but I wouldn't recommend to overuse composite primary keys for mysql INNODB tables. For INNODB engine Primary Key is also a clustered index which defines physical location of the row data. Frequent changes of any columns which are part of PK will cause external fragmentation, and ,as a result, worse performance. Unique key on 2 columns will work much better.
Surely, composite PK is a good choice when you implement many-to-many relationship
As others have stated... yes you can... However, in many systems the tables will have "surrogate" auto-increment keys which would be your "PRIMARY" and used in most cases for your joins... this to prevent duplication of such other data as samples like MyCol1, MyCol2, MyCol3 and FirstName, SurName in other tables.
In addition, you can have a "candidate" key which is a UNIQUE index for the table that is IN ADDITION to your primary, such as duplicate entry prevention, or by "lookup" purposes. Doing a lookup by a person by name is one thing. Then, when you have their "Surrogate" ID, THAT is the key that would be used elsewhere in the system... Ex: How many times would you find a "Bob Smith" with completely unrelated entries... But ID #3892 "Bob Smith" at 123 Anyplace is different than ID#28928 "Bob Smith" at 983 Wrong Street.