I am working on creating a database from an ER diagram however I don't think some of my primary and foreign keys are correct. The tables that I don't think they are correct in is the primary key in section and the FK and PK in enrolled table. I also don't think I am properly enforcing my FK constraints so that I can detect referential integrity violations.
Here is the ER Diagram I am basing my database off of.
Here are the tables that I have made
CREATE TABLE Student
(
StudentId INTEGER,
FName VARCHAR(20),
LName VARCHAR(20),
DOB CHAR(10),
Major VARCHAR(20),
PRIMARY KEY(StudentId)
);
CREATE TABLE Phone
(
sID INTEGER,
Pnumber CHAR(20),
Type CHAR(3),
PRIMARY KEY(Pnumber)
);
CREATE TABLE Class
(
ClassId VARCHAR(6),
Description VARCHAR(30),
NumCredits Integer,
Prereq VARCHAR(20),
PRIMARY KEY(ClassId)
);
CREATE TABLE Section
(
ClassId VARCHAR(6),
SecNo CHAR(10),
Semester CHAR(4),
ClassRoom VARCHAR(6),
TimeOffered VARCHAR(18),
PRIMARY KEY(SecNo),
FOREIGN KEY(ClassId) REFERENCES Class(ClassId)
);
CREATE TABLE Enrolled
(
StudentId INTEGER,
SecNum VARCHAR(40),
ClassId VARCHAR(8),
Semes VARCHAR(6),
GorDD VARCHAR(30)
FOREIGN KEY(ClassId) REFERENCES Section(ClassId),
FOREIGN KEY(StudentId) REFERENCES Student(StudentId)
);
CREATE TABLE Professor
(
EmpId INTEGER,
FName VARCHAR(10),
LName VARCHAR(10),
Dept VARCHAR(2),
QualClass VARCHAR(40),
PRIMARY KEY (EmpId)
);
CREATE TABLE Teaches
(
Class VARCHAR(5),
Section INTEGER,
Semester CHAR(4),
EmpId INTEGER,
FOREIGN KEY (EmpId) REFERENCES Professor(EmpId)
);
CREATE TABLE Qualified
(
EmpId INTEGER,
ClassId VARCHAR(5)
);
Thank you for the help in understanding how to create a DB from an ER diagram.
You really should have a simple, standardized, AUTO_INCREMENT PRIMARY KEY for every table. That makes referring to specific records a lot easier. It's also better to refer to tables by their primary key only when building relationships. String primary keys can be trouble, especially if those strings can change.
Additionally, your arbitrary limitations on string lengths is extremely annoying. Who are you to say people should only have names twenty characters long, or professors can have names only ten long? That's really sloppy. Unless you've got a very good reason, leave it wide open for these sorts of free-form fields, default VARCHAR(255). Hard drives are measured in terabytes today and you'd need to have a hundred million students to fill up your drive with name data.
Otherwise, as a database this is okay. I'd probably discard this schema entirely and rebuild from your entity diagram, a great tool to have by the way, using the conventions of whatever development framework I was using. For example, Ruby on Rails, Django, Drupal, and Tapestry will all have their own ideas on how to name tables.
After a quick look, it looks to me like you would want to have a compound primary key for Section made up of ClassId, SecNo, and Semester assuming those three attributes make up the uniqueness scope for the entity of Section. You could also just have a SectionID that is unique (such as an auto-incrementing int)
For Enrolled, I would make an auto-incremented primary key and have a foreign key that links to the Section table depending on how you solve that entity/table's uniqueness.
Hope this helps. Of course, there are many ways to go about this.
It is usually more useful and more practical to use primary keys specific to the database domain because in real life most entities don't have truly unchanging and unique keys perfectly suited for primary keys.
For example, data entry errors may necessitate the change of a student ID in the database. If you use a property that ends up changing then you'll have to create (effectively) a new student for every change in primary key(StudentId).
The alternative solutions:
Use an automatic key in the database and make the StudentId unique but not primary.
Use a StudentId as the primary key and have it be auto updated every
time it changes in the parent table.
I don't recommend the second option because it is just a workaround the old problem.
Related
----Scheme1----
CREATE TABLE college (
id INT AUTO_INCREMENT,
name VARCHAR(250) NOT NULL,
address VARCHAR(250),
PRIMARY KEY (id)
);
CREATE TABLE student (
college INT NOT NULL,
username VARCHAR(50) NOT NULL,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
CONSTRAINT pk PRIMARY KEY (college,username)
);
CREATE TABLE subject (
college INT NOT NULL,
id INT NOT NULL,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
CONSTRAINT pk PRIMARY KEY (college,id)
);
CREATE TABLE marks (
college INT NOT NULL,
student VARCHAR(50) NOT NULL,
subject INT NOT NULL,
marks INT NOT NULL,
// forget about standard for this example
FOREIGN KEY (college) REFERENCES college(id),
FOREIGN KEY (student) REFERENCES student(username),
FOREIGN KEY (subject) REFERENCES subject(id),
CONSTRAINT pk PRIMARY KEY (college,subject,student)
);
----Scheme2----
CREATE TABLE college (
id INT AUTO_INCREMENT,
name VARCHAR(250) NOT NULL,
address VARCHAR(250),
PRIMARY KEY (id)
);
CREATE TABLE student (
college INT NOT NULL,
id BIGINT NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
PRIMARY KEY (id)
);
CREATE TABLE subject (
college INT NOT NULL,
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
PRIMARY KEY (id)
);
CREATE TABLE marks (
student VARCHAR(50) NOT NULL,
subject INT NOT NULL,
id BIGINT NOT NULL AUTO_INCREMENT,
marks INT NOT NULL,
// forget about standard for this example
FOREIGN KEY (student) REFERENCES student(id),
FOREIGN KEY (subject) REFERENCES subject(id),
PRIMARY KEY (id)
);
Looking at the above database schemes it looks like Scheme1 will give better performance while searching for the result of a specific student and faster in filtering results but it feels like it is not in all normalized forms. While Scheme2, on the other hand, looks to be fully normal but might require more JOIN operations to fetch certain results or filter the data.
Please tell me if I'm wrong about my Schemes here, also tell me which one is better?
I would go for Schema 2: when it comes to reference a table, it is easier done by using a single column (auto_incremented primary key in Schema 1) than a combination of columns (coumpound primary keys in Schema 1). Also, as commented by O.Jones, Schema 2 assumes that two students in the same college cannot have the same name, which does not seem sensible.
There are other issues with Schema 1, eg the foreign key that relates the marks to students is malformed (you would need a coumpound foreign keys that include the college id instead of just the student name).
With properly defined foreign keys referencing primary keys, performance will not be a problem; joins perform good in this situation.
But one flaw should be fixed in Schema 2, that is to store a reference to the college in the marks table. You don't need this, since a student belongs to a college (there is a reference to the college in the student table).
Also, I am unsure that a subject should belong to a college: isn't it possible that the same subject would be taught in different colleges?
Finally, I would suggest giving clearer names to the foreign key columns, like student_id instead of student, and college_id instead of college.
It's difficult to assess whether a schema is normalized without first knowing the the relationships between entities. Can a student be associated with only one college? Can a student be associated multiple times over with the same subject, getting different marks?
Declaring foreign keys maintains referential integrity but slows down insertions and updates. You can get the same functionality without declaring the fks, but you may end up with some orphaned records. The fact that a particular index is used for a fk, or not, makes no difference to SELECT query performance.
JOIN operations use indexes. So do fks. So if you have the correct indexes, your JOIN operations will be efficient. But it's impossible to know which indexes are the best without knowing your JOIN queries.
Conventionally, each table's id column comes first. And many designers name each id column after the table in which it appears, for example college.college_id rather than college.id. That makes JOIN queries slightly easier to read.
You should use a surrogate primary key in the student table (student.student_id) rather than using the student's name as part of the primary key. JOINing on id values is faster than joining on VARCHAR() values. And, some students may share names. (In the real world, peoples's dates of birth accompany their names in tables: it helps tell people apart.)
I think your marks table should contain these columns:
CREATE TABLE marks (
student_id INT NOT NULL,
subject_id INT NOT NULL,
marks INT NOT NULL,
// foreign keys as needed
PRIMARY KEY (student_id, subject_id)
);
Can a student have multiple marks for the same subject? In that case use a marks_id as the pk instead of (student_id, subject_id).
So I have 3 tables that are still in the logical ERD state. Devices, HearingDevices and Vision Devices. Hearing and Vision devices are derived from the Device entity.
I'm just pondering, is there any way I can create a entry where when I enter a device with ID 001 in the device entity, it will replicate in my two sub entities i.e. hearing and vision device entities.
Even if thats not possible. How would I display the corresponding hearing or vision device when I print out the device information ( I know you can use a simple embedded select statement but I'm looking for alternative options )
My code is down below,
CREATE TABLE Device (
deviceCatalogID varchar(5),
deviceCatalogName varchar(20),
deviceDescription varchar(300),
availabilityStatus boolean,
CONSTRAINT pk_device_catalogID PRIMARY KEY (deviceCatalogID)
);
CREATE TABLE Visual_Device (
deviceCatalogID varchar(5),
frBrand varchar(20),
frModel varchar(20),
lensSerialN varchar(20),
lensVisionType varchar(20),
lensTint set('1','2','3'),
lensThinnessLevel set('1','2','3'),
CONSTRAINT pk_visionDevice_catalogID PRIMARY KEY (deviceCatalogID),
CONSTRAINT fk_visualDevice_catalogID FOREIGN KEY (deviceCatalogID) references device(deviceCatalogID)
);
CREATE TABLE Hearing_Device (
deviceCatalogID varchar(5),
hdMake varchar(20),
hdModel varchar(20),
CONSTRAINT pk_hearingDevice_catalogID PRIMARY KEY (deviceCatalogID),
CONSTRAINT fk_hearingDevice_catalogID FOREIGN KEY (deviceCatalogID) references device(deviceCatalogID)
);
Read about database triggers:
https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
You can replicate entries in devive to the other two tables this way:
https://www.db-fiddle.com/f/VAfRc5GA4sjsV3ZYpiVwq/0
I have two (mysql) tables -- company and user. They are structured as follows:
`user`
- id
- company_id (FK to company)
- name
`company`
- id
- name
- admin_user_id (FK to user)
The user table foreign keys to the company table, and vice versa.
I was wondering if the above pattern is ok, and if it's not why it's not, what could be done to improve it.
At a high level, your data model makes sense. However, you have no guarantee that admin_user_id points to a user in the same company. You can solve this by doing:
create table users (
user_id int auto_increment primary key,
company_id int,
name varchar(255),
unique (company_id, user_id) -- redundant but desirable for the foreign key reference
);
create table companies (
company_id int auto_increment primary key,
name varchar(255),
admin_user_id int,
foreign key (company_id, admin_user_id) references users(company_id, user_id)
);
alter table users
add constraint fk_users_company_id
foreign key (company_id) references companies (company_id);
If it is an accurate representation of your business domain then that's what really matters. There is a possible problem in SQL however. SQL only allows one table to be updated at once so either company or user has to come first. Normally you have to allow the constraint to be broken temporarily, either when you insert a new company with no corresponding user, or insert a new user with no corresponding company. To achieve that you can make one of the foreign keys nullable or you can temporarily disable the constraint.
Some data modellers dislike circular dependencies, even in purely conceptual models where the limitations of SQL are irrelevant. A few people will perceive circular dependencies as a modelling mistake - wrongly in my opinion. Disapproval of circular dependencies seems to be associated with ER modelling specifically. Interestingly, circular self-referential dependencies are taken for granted in Object Role Modelling which even has a special notation for them (ring constraints).
I am working on a data model where I need to store Employee's basic details and his rating of skillsets in MySQL database.
The number of skillsets for each employee is more than 100.
So the information I need to store is as following:
Employee ID, Name , Department , Contact info, Skillset1,Skillset2,Skillset3, ... , Skillset115
Is creating one table with approximately 120 columns is good approach?
If not, what is the best practice to deal with this kind of requirement.
No. You should have a separate table with one row per employee and per skill:
create table employeeSkills (
employeeSkillId int auto_increment primary key,
employeeId int not null,
skill varchar(255),
constraint fk_employeeSkills_employeeid foreign key (employeeId) references employees(employeeId)
);
In fact, you should really have two extra tables. The skills themselves should be stored in a separate table and the above should really be:
create table employeeSkills (
employeeSkillId int auto_increment primary key,
employeeId int not null,
skillId int,
constraint fk_employeeSkills_employeeid foreign key (employeeId) references employees(employeeId),
constraint fk_employeeSkills_skillid foreign key (skillId) references skills(skillId)
);
This type of table is called a "junction table", and is common in any properly constructed data model.
You need to create two tables that would handle the skills and the assigned skill for each employee.
This would give you a proper order in your database and also will extend your options in the future. It'll be better in search, add and assign skills to each employee. It's even more organized and would be able to be expanded easily such as adding skills category and sub-category.
The two tables schema should be something like this :
CREATE TABLE Skills (
Skill_ID INT NOT NULL AUTO_INCREMENT,
Skill_Description VARCHAR(250),
PRIMARY KEY (`Skill_ID`)
);
CREATE TABLE EmpolyeeSkills (
ES_ID INT NOT NULL AUTO_INCREMENT,
Skill_ID INT,
Employee_ID INT,
PRIMARY KEY (`ES_ID`),
CONSTRAINT FK_EMPLOYEEID FOREIGN KEY (Employee_ID) REFERENCES Employees(Employee_ID),
CONSTRAINT FK_SKILLID FOREIGN KEY (Skill_ID) REFERENCES Skills(Skill_ID)
);
The Skills table will assign an ID for each skill, and it'll be in a separate table. This will make you have a unique skills list, there won't be any redundancy. Then, you'll use EmployeeSkills to save the assigned skills on each Employee_ID. Which you can use it later on to join it with other records.
The FOREIGN KEY on Employee_ID and Skill_ID will help you in monitoring the skills between them.
The ES_ID primary key for EmpolyeeSkills will be an additional advantage that can be helpful in the future. For instance, if you want to know the latest skill that has been assigned, then your faster approach will be getting the last ES_ID as it's an AUTO_INCREMENT. This is just one advantage from tons of others.
I am trying to create a database containing information from a game for an assignment but am having issues when creating the tables with assigning the primary and foreign keys. Any help would be amazing.
The error code I am getting is: #1215 - Cannot add foreign key constraint on table Boss. It creates the first table fine it just stops working and throws the error at the foreign key when creating table boss.
Within the item table the field Boss needs to be able have the same data entered for multiple different items.
CREATE TABLE item ( ID SERIAL, Name VARCHAR(35), Boss VARCHAR(25), Type VARCHAR(20), Slot VARCHAR(20), PRIMARY KEY (Name,Boss) );
CREATE TABLE boss ( ID SERIAL, Boss VARCHAR(25), Type VARCHAR(20), Location VARCHAR(20), Difficulty INT, PRIMARY KEY (ID, Location), FOREIGN KEY (Boss) REFERENCES item(Boss) );
CREATE TABLE dungeon ( ID SERIAL, Name VARCHAR(25), Location VARCHAR(20), Rating INT, PRIMARY KEY (Name), FOREIGN KEY (Location) REFERENCES boss(Location) );
I can see many things wrong with your db creation script, but I will only stick to the ones that immediately affect getting it to work in the first place:
You should always refer to another table through its primary key and nothing else.
Your references are put in the wrong tables. If you want to refer to a "boss" from "item" then you should do just that and not refer to "item" from "boss".
But the most important thing is that references should be of the same type as the primary keys they refer to.
A composite key is a bad idea when you don't really need one.
So, a working script would be:
CREATE TABLE dungeon ( ID BIGINT(20), Name VARCHAR(25), Location VARCHAR(20), Rating INT, PRIMARY KEY (ID) );
CREATE TABLE boss ( ID BIGINT(20), Type VARCHAR(20), LocationId BIGINT(20), Difficulty INT, PRIMARY KEY (ID), FOREIGN KEY (LocationId) REFERENCES dungeon (ID) );
CREATE TABLE item ( ID BIGINT(20), Name VARCHAR(35), BossId BIGINT(20), Type VARCHAR(20), Slot VARCHAR(20), PRIMARY KEY (ID), FOREIGN KEY (BossId) REFERENCES boss (ID) );
You can adjust it to your needs, but before doing that, I would suggest reading a good book on database design or -at least- a tutorial on basic relational databases principles.