Relationships in same table - mysql

I'm trying to make 2 "one to many" relationships on the same table, as I have employees managed by TLs supervised by SPVs.
Employees table consists of (ID -PK- , name , hire_date ,,,,,) it's the same data for TL and SPV also
on the ERD I've made it as a one to many on the same table but I've no idea how to make it on SQL (I can't detect what should be refer to who)
I've thought about giving up the one to many relationship idea and add a "type" as 1 if employee and 2 if TL and 3 if SPV but i need to know every TL's employees for example (TL#1 have the employees John , Paul, Smith ,... in his team) and so on
**Note: I'm not sure if it's the right thing to make it as a one to many relationship , if there's any other way I'd really appreciate it :)

sql? just put the same table in the REFERENCES clause.
if you can't do it, do it in a separate SQL sentence.
CREATE TABLE EMPLOYEE (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
spv INTEGER UNSIGNED NULL,
...,
PRIMARY KEY(id)
);
ALTER TABLE employee ADD FOREIGN KEY ( spv ) REFERENCES employee (id) ON DELETE RESTRICT ON UPDATE CASCADE

Related

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.

#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.

Designing relationships around an inheritance structure

I have a conceptual question regarding how best to organise my database.
Currently I have four core tables users, teachers, students and notifications. However both the teachers and students tables inherit from the users table so contain the foreign key user_id.
The notifications table as you might have guessed refers to notifications. These need to appear for all users that belong to an employee group i.e. under the employment of another.
Both students and teachers can employ other users.
So the crux is I need an eloquent way of modelling this. The basic workflow of the code would be the below:
getCurrentUser->getAllEmployer(s)->getNotifications
This is the Laravel Eloquent I'm used to $user->employers()->notifications;
Unfortunately it's not as simple as that as in this case an employer can refer to two tables.
So my choices are as follows.
Create an Eloquent Relationship for both the student and teacher
relationship as employers. The shortfall being I need to write if
tests to check if the current user belongs to either and this code
would be repeated frequently.
Add a teacher_id and student_id to
the users table. However one would obviously be redundant in each
record. The chance of needing to add other columns is very likely as
well due to the emergence of new employer entities.
Create an employer_employee table that contains two columns both referencing a user_id. A SQL query would LEFT JOIN both student and
teacher tables with the employer_employee table and then a JOIN
with notifications would return all those relevant. However would
so many joins reduce the speed of the query when compared with the
other options.
Something I haven't considered.
I'm really looking for the most efficient, scalable solution.
Any help is appreciated. If you could clarify why your answer is the most efficient scalable solution as well that would be superb.
There is a similar question here using a Media supertype and adding subtypes of CD, VCR, DVD, etc.
This is scalable in that in creating, say, a BluRay subtype, you create the table to contain the BluRay-specific data and add an entry to the MediaTypes table. No changes needed for existing data or code -- except, of course, to add the code that will work with BluRay data.
In your case, Users would be the supertype table with Teachers and Students the subtype tables.
create table Users(
ID int not null auto_generating,
Type char( 1 ) check( Type in( 'T', 'S' )),
-- other data common to all users,
constraint PK_Users primary key( ID ),
constraint UQ_UserType unique( ID, Type ),
constraint FK_UserTypes foreign key( Type )
references UserTypes( ID )
);
create table Teachers(
TeacherID int not null,
TeacherType char( 1 ) check( TeacherType = 'T' )),
-- other data common to all teachers...,
constraint PK_Teachers primary key( TeacherID ),
constraint FK_TeacherUser foreign key( TeacherID, TeacherType )
references Users( ID, Types )
);
The makeup of the Students table would be similar to the Teachers table.
Since both teachers and students may employ other teachers and students, the table that contains this relationship would refer to the Users table.
create table Employment(
EmployerID int not null,
EmployeeID int not null,
-- other data concerning the employment...,
constraint CK_EmploymentDupes check( EmployerID <> EmployeeID ),
constraint PK_Employment primary key( EmployerID, EmployeeID ),
constraint FK_EmploymentEmployer foreign key( EmployerID )
references Users( ID ),
constraint FK_EmploymentEmployee foreign key( EmployeeID )
references Users( ID )
);
As I understand it, Notifications are grouped by employer:
create table Notifications(
EmployerID int not null
NotificationDate date,
NotificationData varchar( 500 ),
-- other notification data...,
constraint FK_NotificationsEmployer foreign key( EmployerID )
references Users( ID )
);
The queries should be simple enough. For example, if a user wanted to see all the notifications from his employer(s):
select e.EmployerID, n.NotificationDate, n.NotificationData
from Employment e
join Notifications n
on n.EmployerID = e.EmployerID
where e.EmployeeID = :UserID;
This is an initial sketch, of course. Refinements are possible. But to your numbered points:
The Employment table relates employers to employees. The only check if to make user employers cannot employee themselves, but otherwise any user can be both an employee and employer.
The Users table forces each user to be either a teacher ('T') or student ('S'). Only users defined as 'T' can be placed in the Teachers table and only users defined as 'S' can be placed in the Students table.
The Employment table joins only to the Users table, not to both the Teachers and Students tables. But this is because both teachers and students can be both employers and employees, not for any performance reason. In general, don't worry about performance during the initial design. Your primary concern at this point is data integrity. Relational databases are very good with joins. If a performance issue should crop up, then fix it. Don't restructure your data to solve problems that do not yet exist and may never exist.
Well, give this a try and see how it works.

How do I normalize data using microsoft access

I currently have a courses table that has a layout like below.
course_title, course_subject, course_number, instructor, course_id
I need to create a new table and then push over the instructor_id, so I can then access the table via a foreign key id for instructor, but I'm not sure how I would go about getting the data from the courses table over to the new tables such as instructor and also creating the instructor_id fields in the courses table. I hope this question makes sense. I'm importing a flat file from microsoft excel.
Let's first define the schemas for our output tables. The courses table should be something like:
title varchar(100) not null
subject varchar(100) not null
[number] varchar(5) not null unique
id long primary key
instructor_id long not null references instructors (id)
And the instructors table should be:
id autoincrement primary key
[name] varchar(100) not null unique
Let's call your current table courses_old. I may be off by a bit but I'm sure you can adjust for your needs.
So the problem is to get from courses_old to courses and instructors. First we fill up the instructors table:
insert into instructors ([name])
select distinct instructor
from courses_old
Then we fill up courses with matching instructors from instructors:
insert into courses (
title
, subject
, [number]
, id
, instructor_id
) select
co.course_title
, co.course_subject
, co.course_number
, co.course_id
, i.id
from courses_old as co
inner join instructors as i
on co.instructor = i.[name]
That should do it. But obviously you need to verify. Finally, drop the courses_old table and compact the DB file!
Optionally, you can make courses.id an autoincrement field if you're willing to just give them all new IDs. That should be a simple adjustment to the above.

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.