Construction of mysql table - mysql

I have project for school competition in timekeeping and I am stuck to solve tables construction.
Look at this following examples.
This can happen ->
Competition | Contestants
Swiming | John Smith
Driving | John Smith
You can see that same name is there twice, but not in same competition.
This situation is wrong, so how can i prevent following situation ->
Competition | Contestants
Swiming | John Smith
Swiming | John Smith
I want to avoid duplication in the same competition.

If you can't change the table structure of the table, you could add a unique constraint on the combination of the competition and contestant:
ALTER TABLE competitions
ADD CONSTRAINT competitions_unq UNIQUE (competition, contestant);
But this really isn't a great solution. A more idiomatic approach would be to have separate tables for competitions and contestants, and then have an m:n table to join them:
CREATE TABLE competitions (
id INT PRIMARY KEY,
name VARCHAR(100),
-- other columns
);
CREATE TABLE contestants (
id INT PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100),
-- other columns
);
CREATE TABLE competition_contestants (
competition_id INT NOT NULL,
contestant_id INT NOT NULL,
PRIMARY KEY (competition_id, contestant_id),
FOREIGN KEY competition_id REFERENCES competition(id),
FOREIGN KEY contestant_id REFERENCES contestant(id)
);

Related

#1452 - Cannot add or update a child row: a foreign key constraint fails

I am trying to insert some data into the table User. The User table has 2 foreign keys: StudentID and StaffID.
I want to be able to enter either StaffID or StudentID which should link to the relevant table(that already has either the StudentID or StaffID). The table User can only have StaffID or StudentID. Can Anyone help?
INSERT INTO `User` (`UserName`, `Email`, `StudentID`,`StaffID`,`Paasword`)
VALUES ('phill', 'ph#lms.com', '', '2201','654321');
Ok, so prepare yourself. This answer is long, but thorough.
Short Answer:
As referenced in this answer by #HLGEM you can accomplish what you're asking by making the primary keys in the STAFF and STUDENT table, presumably the values StaffID and StudentID NULLABLE. Here is the relevant snippet from his answer:
To allow nulls in an FK generally all you have to do is allow nulls on the field that has the FK. The null value is separate from the idea of it being an FK.
You can do this in your table definition adding NULL to your create statement similar to the following by specifying:
CREATE TABLE STUDENT (
StudentID INT UNSIGNED NULL PRIMARY KEY AUTO_INCREMENT
...
)
The above is an example of how to apply this to the STUDENT table. The STAFF table would have a similar approach. Note, the extra values are there as a suggestion based on general configuration that is common when configuring ID fields.
LONG ANSWER:
As #HLGEM mentioned in his answer, there are some times when it is appropriate to have a foreign key constraint that can be NULL. However, in your case, it suggestions that the data is not fully normalized. The need for a NULL foreign key can be eliminated in your case with a little table refactoring. Let's explore an additional possibility when designing your database tables:
Case Study:
Let's begin with the following assumption. Since you said in your question:
I want to be able to enter either StaffID or StudentID which should link to the relevant table(that already has either the StudentID or StaffID). The table User can only have StaffID or StudentID
It is probably a safe assumption to say that a user has to be a staff member or a student but not both. That assumption makes a strong use case for having a UserType table. Let's alter the USER definition to support a UserTypeId and create the USER_TYPE table:
# USER TYPE Table Definition
CREATE TABLE USER_TYPES (
UserTypeId TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
UserType VARCHAR(25) NOT NULL
) ENGINE=INNODB CHARSET=UTF8;
# USER TABLE Definition
CREATE TABLE USERS (
UserId INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
Name VARCHAR(25) NOT NULL,
Email VARCHAR(50) NOT NULL,
Password VARCHAR(100) NOT NULL,
UserTypeId TINYINT UNSIGNED NOT NULL,
FOREIGN KEY(UserTypeId) REFERENCES USER_TYPES(UserTypeId)
) ENGINE=INNODB CHARSET=UTF8;
Notice that in this new schema, we no longer have a reference to StudentID or StaffID, but instead we have a UserTypeId. There are two benefits to this approach:
USERS.UserTypeId is a foreign key reference to USER_TYPES.UserTypeId but no longer has to be NULLABLE.
You can have more user types than just Student or Staff.
For our case study here, let's create two user types Student and Employee (I'll explain why I'm not using Staff here in a little). Let's also go ahead and populate the USERS table with the initial values for Phill, your employee you mentioned in your question.
INSERT INTO USER_TYPES(UserType)
VALUES("Employee"),("Student");
INSERT INTO USERS(Name,Email,Password,UserTypeId)
VALUES("phill","ph#lms.com","654321",1);
Excellent! Our new design is coming together quickly. Now let's create two additional tables, one called STUDENTS and one called EMPLOYEES. In this case, I chose to go with EMPLOYEES instead of STAFF because it allows you to be more flexible in how you define an employee. As you'll see in the definition, you can further define a user type of Employee with an ENUM value of either Faculty, Staff or Administrative. Think of this as a subtype of the general type Employee. Note that you could also create another join table like we did for USER_TYPES, for instance one called EMPLOYEE_TYPES. Either method is appropriate. I chose to use an ENUM instead of another foreign key to demonstrate an additional concept you could use if you only have a handful of choices.
So on to those last two table definitions:
# STUDENTS Table Definition
CREATE TABLE STUDENTS(
StudentId INT UNSIGNED PRIMARY KEY,
Year ENUM('Freshman','Sophmore','Junior','Senior') NOT NULL,
FOREIGN KEY(StudentId) REFERENCES USERS(UserId)
) ENGINE=INNODB CHARSET=UTF8;
# EMPLOYEES Table Definition
CREATE TABLE EMPLOYEES (
EmployeeId INT UNSIGNED PRIMARY KEY,
EmployeeType ENUM('Faculty','Staff','Administrative') NOT NULL,
FOREIGN KEY(EmployeeId) REFERENCES USERS(UserId)
) ENGINE=INNODB CHARSET=UTF8;
Notice that these two tables do not have their own Id column, but instead, reference the Id from the USERS table as a foreign key constraint. This makes sense because you have to be a user before you can be a student or an employee.
Finally, let's add some employee data for Phill:
INSERT INTO EMPLOYEES(EmployeeId,EmployeeType)
VALUES(1,"Faculty");
That was a lot, but now you'll begin to reap the benefits. Everything above was foundational in that it offers a fully normalized approach to your database layout with additional flexibility and without the need for a NULLABLE foreign key.
Retrieving data in this instance is easy and we don't even have to know if Phill is an employee or a student. Let's look at an example query:
SELECT
u.UserId,
u.Name,
u.Email,
ut.UserType,
s.*,
e.*
FROM USERS AS u
INNER JOIN USER_TYPES AS ut ON u.UserTypeId = ut.UserTypeId
LEFT JOIN STUDENTS AS s ON u.UserId = s.StudentId
LEFT JOIN EMPLOYEES AS e ON u.UserId = e.EmployeeId
WHERE u.Email = "ph#lms.com";
which returns:
+--------+--------+-------------+-----------+-----------+--------+------------+--------------+
| UserId | Name | Email | UserType | StudentId | Year | EmployeeId | EmployeeType |
+--------+--------+-------------+-----------+-----------+--------+------------+--------------+
| 1 | phill | ph#lms.com | Employee | (null) | (null) | 1 | Faculty |
+--------+--------+-------------+-----------+-----------+--------+------------+--------------+
Conclusion:
Live Example: sqlfiddle
So there you have it. By performing a LEFT JOIN between STUDENTS, EMPLOYEES and the USERS table, you'll pull back all values that exist in either of the two tables and all the default user values. From here, it's a simple as checking for NULL on StudentId or EmployeeId to determine which user type you're working with.

Implementing Tree Structure In MySQL Database

this question may asked by several people.But still I didn't get a right answer. So here it is
I want to load Continents, Countries and Cities to below combo boxes. So I need to make relation between those. Means city need be in a country and country belongs to a continent. So of course I am talking about a tree structure. So how should I implement this in MYSQL database in efficient way? How many tables need? How to do the relation among those?
Here is the image.
http://i.stack.imgur.com/st4oz.jpg
There are formal ways to represent arbitrary trees, but I think the following is simpler and should be sufficient:
CREATE TABLE Continents (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
PRIMARY KEY (id),
UNIQUE (name)
)
CREATE TABLE Countries (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
continent INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (continent) REFERENCES Continents(id),
UNIQUE (name)
)
CREATE TABLE Cities (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
country INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (country) REFERENCES Countries(id),
UNIQUE (name)
)
I didn't test the code, so there may be some syntax errors. I hope the intent is clear, though.
#Vmai raises an excellent point in his comment on the question.
My solution would be to have the "problem countries" once in the Countries table for every continent they are in. (So Turkey would be twice in the database, once with continent set to the id of Asia, and once to the id of Europe. Same for Russia.) The same goes for cities, of course.
All you need is one table. As long as the structure of data is the same, there's no reason to have three tables. And this way, you don't care about the depth and how the locations administratively are organized.
+-------------------------+
| locations |
+-------------------------+
| location_id (int) | primary key
| location_name (varchar) |
| parent_id (int) | index
+-------------------------+
Or another solution
+-------------------------+
| locations |
+-------------------------+
| location_id (int) | primary key
| location_name (varchar) |
| left (int) |
| right (int) |
+-------------------------+
To be explained...

Can a foreign key refer to the primary key of its own table?

I am creating a MySQL employee database for work and I want it to store the supervisor of the employee.
Suppose I have a table called 'employee' with the fields 'id', 'first_name', 'last_name', and 'supv_id' where 'id' is the primary key and 'supv_id' is a foreign key that refers to and employee ID.
Currently I have 'supv_id' as a foreign key that points to a separate table 'supervisor'. This table simply consists of 'id' and 'empl_id' which points back to the employee table. However, if there is a way to simply make 'supv_id' in 'employee' to point to 'employee.id', this would eliminate the need of my 'supervisor' table altogether. Here is an example:
+----+--------+-----------+---------+
| id | f_name | l_name | supv_id |
+----+--------+-----------+---------+
| 1 | Han | Solo | NULL | //Or 0?
| 2 | Luke | Skywalker | 1 |
+----+--------+-----------+---------+
In short, I want 'supv_id' to point to another employee. Does this make sense? How would I go about doing this?
Thanks!
Edit: fixed table
You can create such a table as following:
CREATE TABLE laya2 (
id INT NOT NULL PRIMARY KEY,
f_name VARCHAR(20),
l_name VARCHAR(20),
supv_id INT,
INDEX supv_id_idx (supv_id),
FOREIGN KEY (supv_id)
REFERENCES laya2(id)
ON DELETE SET NULL -- example for an action
) ENGINE=INNODB;
My example sets the reference option to SET NULL, because I think it's the logical one here. If an employee who supervises others left, then those employees have no supervisor first. Another option would be to have NO ACTION because you could easily identify those employees without a valid supervisor and find a new supervisor for them. ON DELETE CASCADE would be wrong here, because those employees won't leave at the same time ...
You could insert employees with
INSERT INTO laya2 VALUES
(1, 'Han', 'Solo', NULL),
(2, 'Luke', 'Skywalker', 1);
(two successful inserts), but not with
INSERT INTO laya2 VALUES
(3, 'Anakin', 'Skywalker', 0);
This statement will fail because the foreign key constraint fails.
Deleting Han Solo will change the supv_id for Luke Skywalker to NULL, because of the reference option ON DELETE SET NULL
DELETE FROM laya2 WHERE id = 1; -- this will set the supv_id for Luke Skywalker to NULL
Yes, join the table to itself. Here's one of many ways:
SELECT a.l_name AS employee, b.l_name AS supervisor
FROM employee AS a, employee AS b
WHERE a.supv_id = b.id -- link tables
AND a.id = 2 -- get employee
Returns:
employee | supervisor
----------+-----------
Skywalker | Solo
Yes, you can define a foreign key that refers to the primary key of its own table.
create table employee (id int(10),
f_name varchar(10),
l_name varchar(10),
supv_id int(10)) ENGINE=InnoDB;
alter table employee add primary key (id);
alter table employee add foreign key (supv_id) references employee (id);
Employees without supervisor must have NULL in the supv_id column.

Use a Table as a Variable in SQL

I have two tables classroom and computer and currently computer is a variable in the table classroom
CREATE TABLE classroom_tbl
(
room_id INT AUTO_INCREMENT PRIMARY KEY,
teacher_name VARCHAR(30),
subject_name VARCHAR(30),
computer VARCHAR(30)
);
and I want to make it so instead of being a VARCHAR in the classroom table the variable computer calls the computer table
CREATE TABLE computer_tbl
(
computer_id INT AUTO_INCREMENT PRIMARY KEY,
computer_type VARCHAR(30),
computer_status INT
);
Is there any way to do this? I've tried UNION and INNER JOIN but I always get an error that says that my columns are different sizes. Which makes sense because classroom is bigger than computer. Thanks for any help you can give!
I believe you are new to SQL and have some experience in programming. SQL does not have variables like we do have in programming langauages such as C/C++/java. Rather SQL tables relate to each other with relationships such as foreign key relationship. You need to go through SQL tutorials for understanding more about relationships, here is a link to one of those:
http://www.functionx.com/sql/Lesson11.htm
In order to use the JOINS you need to have Primary-foreign key relationship between the two tables. You may have to create your table like this:
CREATE TABLE classroom_tbl
(
room_id INT AUTO_INCREMENT PRIMARY KEY,
teacher_name VARCHAR(30),
subject_name VARCHAR(30),
computer_id INT REFERENCES computer_tbl(computer_id)
);
Since a given classroom can have many computers in it, but a given computer can only be in one classroom at a time, it makes more sense to have classroom as a foreign key on the computer table, rather than vice versa:
CREATE TABLE classroom_tbl
(
room_id INT AUTO_INCREMENT PRIMARY KEY,
teacher_name VARCHAR(30),
subject_name VARCHAR(30)
);
CREATE TABLE computer_tbl
(
computer_id INT AUTO_INCREMENT PRIMARY KEY,
computer_type VARCHAR(30),
computer_status INT,
room_id INT
);
To see which computers are in each room, try a query like:
select r.room_id, r.teacher_name, r.subject_name,
c.computer_id, c.computer_type, c.computer_status
from classroom_tbl r
left join computer_tbl c on r.room_id = c.room_id
If anyone comes across this, what I wanted to do was not possible. You can only reference other columns in other tables or create foriegn keys. Unfortunatly you cannot reference an entire table.

Database structures Phpadmin in MySQL CodeIgniter

Imagine we have a phpadmin database and we have a table for students and student_music and student_friend student_friend_music. Does this make sense performance wise to have four tables? or do you think we need to have three tables for students students_friends student_music and table for music. How does facebook stores friends relationship in it's database?
Other thing is that I designed the data base for both. I don't know if I see any difference but I think once the users increase one would beat other performance wise?
So my question concerns the performances of querying:
Is this better to have more tables or
Can we have duplicates.
Do you know any good book, tutorial or reference I can study to know about relational data bases in Php my admin and mysql.
Update:
Table Student can have many to many relation with itself.
Table Music has Many to Many with the student as well.
Student id Student_friend Music id STUDENT_MUSIC
A 1 1-3 YT 1 1 3
B 2 2-3 RU 2 2 3
C 3 PI 3 3 1
3 2
So I am using something called Data Mapper in code igniter which causing me a headache but this sounds like a structure I am thinking now.
table suggestions:
table_students (contains students info, etc)
table_music (music pref of studs with student id from table_students)
table_friends (contains student id's from table students and flag value either friend or not friend)
Check out this link for a mysql introduction and the wikipedia article on relational databases. Read about tables, primary and foreign keys. Before worrying about performance you need to address the structure of your database.
Try (One-to-Many:A student can own many pieces of music and have one friend):
CREATE TABLE Student(
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
first_name VARCHAR(30),
last_name VARCHAR(30),
friend_id INT)
CREATE TABLE Music(
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
music_title VARCHAR(30),
music_student_id INT)
FOREIGN KEY (music_student_id) REFERENCES Student(id)
ON DELETE CASCADE
Or Try (Many-to-Many:Many students can own many pieces of music and have many friends):
CREATE TABLE Student(
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
first_name VARCHAR(30),
last_name VARCHAR(30))
FOREIGN KEY (id)
REFERENCES StudentMusic (Student_id)
ON DELETE CASCADE
CREATE TABLE Music(
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
music_title VARCHAR(30),
FOREIGN KEY (id)
REFERENCES StudentMusic (Music_id)
ON DELETE CASCADE
CREATE TABLE StudentMusic (
Student_id INT NOT NULL AUTO_INCREMENT,
Music_id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (Student_id,Music_id)
CREATE TABLE Friendships(
student_A_id INT,
student_B_id INT)
PRIMARY KEY (student_A_id,student_B_id)
Handling the data views of the relationships can be shown using a Select statement. In the One-to-Many design finding a Student's music uses the following query:
Select Student.first_name,Student.last_name,Music.music_title
FROM Student
LEFT JOIN Music on (Student.ID=Music.music_student_id)
Part of designing a database is figuring out what relationships you will need to query.
Also look into normalizing databases.