Adding primary/foreign keys and referencing other tables - mysql

Im having some troubles with key referencing. The Error comes from when i try to insert data into Table Mark
INSERT INTO Mark(examID, studentID, result, occured, noOFAttempts)
VALUES ('B10', '1', '67', '11-JUL-07', '1');
I get the error:
integrity constraint violated - parent key
not found
Context :
The tables Exam and Student represent data about college exams and
students. The exam results for the students, including the number of
attempts a student has had at an exam (noOfAttempts), are recorded in
table Mark by using the id column from Exam and the id column from
Student. Both id columns have unique values . A student has only the
latest result recorded for each exam.
Write a SQL command to create the Mark table. Include the primary keys
and foreign keys apparent in the tables specified above.
CREATE TABLE Exam (
id VARCHAR(255),
subject VARCHAR(255),
noOfStudents INT,
PRIMARY KEY (id));
-
CREATE TABLE Student (
id INT,
name VARCHAR(255),
PRIMARY KEY (id));
-
CREATE TABLE Mark (
examID VARCHAR(255),
studentID INT,
result INT,
occured DATE,
noOFAttempts VARCHAR(255),
FOREIGN KEY (noOFAttempts) REFERENCES Exam(id),
FOREIGN KEY (noOFAttempts) REFERENCES Student(id));
How do i fix the error i know its to do with wrong referencing, thanks

Some of the logic behind the Mark table makes sense to me. It relates exams to the students who took those exams. But the motivation to make noOfAttempts a foreign key does not seem to serve much purpose. There are two foreign keys in that table, examID and studentID, and the combination of these two fields is also a primary key. Here is what the Mark definition might look like to avoid these errors:
CREATE TABLE Mark (
examID VARCHAR(255),
studentID INT,
result INT,
occured DATE,
noOFAttempts VARCHAR(255),
FOREIGN KEY (examID) REFERENCES Exam(id),
FOREIGN KEY (studentID) REFERENCES Student(id),
PRIMARY KEY (examID, studentID)
)
Again, I don't see the point of making noOfAttempts a key of any kind, rather I think it should just be one regular column in the Mark table.
Edit per request from Gordon:
When you made your insert, you attempted to create a record in Mark which referred to parent records which did not exist. In the case of your original table, you attempted to insert '1' as the noOfAttempts, but this ID did not exist in either the Exam and/or Student tables.

Related

Create composite primary key with a name so I can reference it

At a workplace they recycle punchcard ids (for some strange reason). So it is common to have past employees clashing with current employees. As a workaround I want to have employee punchcard id, employee name+surname as the unique primary key (fingers crossed, perhaps add date-of-birth and even passport if available). That can be accomplished with
PRIMARY KEY (pid,name,surname).
The complication is that another table now wants to reference an employee by its above primary key.
Alas, said PK has no name! How can I reference it?
I tried these but no joy:
PRIMARY KEY id (pid, name, surname),
INDEX id (pid, name, surname),
PRIMARY KEY id,
INDEX id (pid, name, surname) PRIMARY KEY,
Can you advise on how to achieve this or even how to reference a composite primary key?
Update:
The table to store employees is em.
The table which references an employee is co (a comment made by an employee).
Ideally I would use pid (punchcard id) as the unique id of each employee. But since pids are recycled, this is not unique. And so I resorted to creating a composite key or an index which will be unique and can reference that as a unique employee id. Below are the 2 tables without the composite key. For brevity, I abbreviated table names and omitted surname etc. So the question is, how can I reference an employee whose id is composite from another table co.
CREATE TABLE em (
pid INT NOT NULL,
name VARCHAR(10) NOT NULL
);
CREATE TABLE co (
id INT primary key auto_increment,
em INT,
content VARCHAR(100) NOT NULL,
constraint co2em_em_fk foreign key (em) references em(pid)
);
If another table wants to reference this one by a composite key, you don't need it to have a name - just the list of fields will do. E.g.
CREATE TABLE other_table (
ID INT PRIMARY KEY AUTO_INCREMENT,
pid *defintion*,
name *defintion*,
surname *defintion*,
..., -- other fields, keys etc.
FOREIGN KEY (pid, name, surname) REFERENCES employees(pid, name, surname)
);
UPD: If you expect that the set of the fields inside PK might change and you can't make a simpler PK (auto-increment integer for example) for the original table, then your best bet might be something like this:
CREATE TABLE employee_key (
ID INT PRIMARY KEY AUTO_INCREMENT,
pid *defintion*,
name *defintion*,
surname *defintion*,
FOREIGN KEY (pid, name, surname) REFERENCES employees(pid, name, surname)
);
-- and then reference the employees from other tables by the key from employee_key:
CREATE TABLE other_table(
ID INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT NOT NULL,
... -- other fields, indexes, etc...
FOREIGN KEY (employee_id) REFERENCES employee_key(ID)
);
Then if you have a change in employee table PK, you'll only need to update employee itself and employee_key, any other tables would stay as is.
If you CAN, however, change the original employees table, I would recommend something like this:
CREATE TABLE employees(
ID INT PRIMARY KEY AUTO_INCREMENT,
pid *defintion*,
name *defintion*,
surname *defintion*,
... -- other fields, keys, etc.
UNIQUE KEY (pid, name, surname)
);
Then you'll have to maintain the logic of generating new pid's in your code, though, or have them in some side table.
UPD2: Regarding inserts and updates.
As for inserts: you need to insert these explicitly - otherwise how would you expect the relation to be established? If you're using an ORM library to communicate with your database, then it might provide you with the methods to specify linked objects without explicitly adding the IDs, but otherwise to insert a row into employees, employee_key and other_table you need to first INSERT INTO employees(...) ;, then get perform a separate INSERT for the employee_key (knowing the key fields you've just added to employees), get the auto-generated key from employee_key and then use that to perform inserts to any other tables.
You might simplify all this by writing an AFTER INSERT trigger for employees table (that would automatically create a row in employee_key) and/or performing your inserts via a stored procedure (that will even return back the key of the newly inserted row in employee_key). But still this work needs to be done, MySQL won't do it for you by default.
Updates are a bit easier, since you can specify ON UPDATE CASCADE when adding the foreign key - in that case a change to one of the fields in the employees will automatically trigger the same change in any tables that reference employees by this key.
You would define it
CONSTRAINT id
PRIMARY KEY (pid, name, surname)
But you should read more about how MySQL uses INDEXES and how to optimize them
https://dev.mysql.com/doc/refman/8.0/en/optimization-indexes.html

Best approach to store 100+ columns in one table in MySQL

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.

Unknown multiple foreign keys to the same table

So I've got a table :
CREATE TABLE Commande
(
id_commande int NOT NULL AUTO_INCREMENT PRIMARY KEY,
client_id int,
livreur_id int,
plat_id int,
dessert_id int,
prix_total int,
heure_estime time,
FOREIGN KEY (client_id) REFERENCES Client(id_client),
FOREIGN KEY (livreur_id) REFERENCES Livreur(id_livreur),
FOREIGN KEY (plat_id) REFERENCES Plat(id_plat),
FOREIGN KEY (dessert_id) REFERENCES Dessert(id_dessert)
) ENGINE=InnoDB;
And in this table, I've got a plat_id and dessert_id, these means that each client can order a plat and a dessert, but I want it to be like each client can order multiple plat and multiple dessert and I don't know the quantity each client is going to order. How to do do this? I hope my question is explicit enough.
You're looking for a many-to-many relationship here. You can achieve that using a 'junction table' that relates every plate to every "commande". The table would have 2 foreign keys, one to the id_commande in the commande and one to plat_id in the Plat table. Thus, if the user with id_commande 1 eats two plates (1 and 2), you will be able to reflect that by adding 2 records to that table:
First record: id_commande: 1, plat_id: 1
Second record: id_commande: 1, plat_id: 2
You can add another table to relate the commande table with dessert as well.

query with foreign key

project assignment is n to n relationship where n can be zero.
pid is primary key for the project table
eid is primary key for the employee table
a project may not be assigned to any employee.similary an employee may not have any project in his hand.
how to write this query? eid should take value as null or the value from the emp table.
pid should either take null or the value from the table project.
IS IT CORRECT.
CREATE TABLE Proj_Assign
(
eid VARCHAR(25),
pid VARCHAR(25),
PRIMARY KEY(eid,pid),
FOREIGN KEY eid REFERENCES employee(eid),
FOREIGN KEY pid REFERENCES project(pid)
);
Give this way:
FOREIGN KEY (t_eid) REFERENCES parent(eid)
ON DELETE CASCADE
Instead of using same eid twice. It is explained in the documentation.
Also, the original parent table should be there before you create this table and you need to manually insert the queries this way:
INSERT INTO `Proj_Assign` (`eid`, `pid`) VALUES (1, 1);
Whatever query you have written is right as per documentation.

How to create a table that uses a whole other foreign table?

Let's say I have this:
CREATE TABLE `classes`
(
`class_ID` INT AUTO_INCREMENT,
FOREIGN KEY (`student_ID`) references `students`(`student_ID`),
PRIMARY KEY (`class_ID`)
)
ENGINE = InnoDB;
The thing here is that each class refers to a single student. But I want it to refer to a whole other table of students, for example:
CREATE TABLE `students`
(
`student_ID` INT AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
PRIMARY KEY (`student_ID`)
)
ENGINE = InnoDB;
Hence, I want multiple student tables, which each table associated to a class. How can I do this? Do i have to declare a single table (e.g. students1, students2, etc.) for each class?
Thanks!
The answer to this will be a little difficult to understand at first. After a while it becomes natural. Is is a well-known design pattern. You need a third table:
create table students_in_courses(studentid, courseid)
In this table you have a row for each student and each course that student is in. You can turn this sentence around: A row for each course and each student that is in this course.
It is a "link table". It is used for M:N mappings.
You can think of this table as an entity, just like students and courses. You could even add additional columns:
create table students_in_courses(studentid, courseid, date_entered, date_exited, grade)
A constant number of tables is enough.
Let me try a different explanation: We could store the information which student is in which course by saving a matrix with the students as its rows and the courses as its columns. Every cell has a bool: student is in this course yes/no.
Now we save this entire matrix in a table like this:
create table students_in_courses(studentid, courseid, is_in_course bit) primary key(studentid, courseid)
For each cell a row. Now we delete all rows with is_in_course = 0 and drop that column because it only contains 1's now. We are back at the original solution. Our "link-table" stores the non-zero cells of the cross-product matrix of the two tables.
No. you create a single table that has foreign keys referencing both tables:
CREATE TABLE students_classes (
student_id int,
classes_id int,
PRIMARY KEY (student_id, classes_id),
FOREIGN KEY (student_id) REFERENCES students (student_ID),
FOREIGN KEY (classes_id) REFERENCES classes (class_ID)
);
That way you can have student (example) #7 in classes (#53 and 37 and 83), student #12 in classes (#53, #212, #7), etc... without conflict.