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 . 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.