我正在尝试将一些数据插入到表User
中。 User
表有2个外键:StudentID
和StaffID
。
我希望能够输入应该链接到相关表格的StaffID
或StudentID
(已经有StudentID
或StaffID
)。表格User
只能有StaffID
或StudentID
。任何人都可以帮忙吗?
INSERT INTO `User` (`UserName`, `Email`, `StudentID`,`StaffID`,`Paasword`)
VALUES ('phill', 'ph@lms.com', '', '2201','654321');
答案 0 :(得分:2)
好的,所以要做好准备。这个答案很长,但很彻底。
简答:
正如answer @HLGEM中所提到的那样,您可以通过在STAFF
和STUDENT
表中创建主键来完成您所要求的内容,大概是值{ {1}}和StaffID
NULLABLE 。以下是他回答的相关摘录:
要允许FK中的空值,通常您只需要在具有FK的字段上允许空值。 null值与它是FK的想法是分开的。
您可以在表定义中将StudentID
添加到您的create语句,类似于以下内容,指定:
NULL
以上是如何将其应用于CREATE TABLE STUDENT (
StudentID INT UNSIGNED NULL PRIMARY KEY AUTO_INCREMENT
...
)
表的示例。 STUDENT
表将采用类似的方法。请注意,额外值是基于配置STAFF
字段时常见的常规配置的建议。
LONG ANSWER:
在他的回答中提到 @HLGEM 时,有时候外键约束可能是ID
是合适的。但是,在您的情况下,它建议数据未完全标准化。通过一点表重构,可以消除对NULL
外键的需求。让我们在设计数据库表时探索另一种可能性:
案例研究:
让我们从以下假设开始。既然你在问题中说过:
我希望能够输入StaffID或StudentID,它应该链接到相关表(已经有StudentID或StaffID)。表User只能有StaffID或StudentID
说一个用户必须是工作人员 或 学生这可能是一个安全的假设>但 不 。该假设为使用NULL
表提供了强有力的用例。让我们更改UserType
定义以支持USER
并创建UserTypeId
表:
USER_TYPE
请注意,在这个新架构中,我们不再引用# 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;
或StudentID
,而是引用StaffID
。这种方法有两个好处:
UserTypeId
。USERS
是对UserTypeId
。USER_TYPES
的外键引用,但不再必须是 NULLABLE 。UserTypeId
或Student
。对于我们的案例研究,让我们创建两个用户类型Staff
和Student
(我将在这里解释为什么我没有使用Employee
)。我们也继续使用您在问题中提到的员工Staff
的初始值填充USERS
表。
Phill
出色!我们的新设计很快就会聚集在一起。现在让我们创建另外两个表,一个名为INSERT INTO USER_TYPES(UserType)
VALUES("Employee"),("Student");
INSERT INTO USERS(Name,Email,Password,UserTypeId)
VALUES("phill","ph@lms.com","654321",1);
,另一个名为STUDENTS
。在这种情况下,我选择使用EMPLOYEES
代替EMPLOYEES
,因为它可以让您更灵活地定义员工。正如您将在定义中看到的那样,您可以进一步定义STAFF
的用户类型,其Employee
值为ENUM
,Faculty
或Staff
。将此视为一般类型Administrative
的子类型。请注意,您也可以创建另一个连接表,就像我们为Employee
所做的那样,例如一个名为USER_TYPES
的连接表。这两种方法都是合适的。我选择使用EMPLOYEE_TYPES
代替另一个外键来演示如果您只有少数选择可以使用的其他概念。
那么最后两个表定义:
ENUM
请注意,这两个表没有自己的# 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;
列,而是引用Id
表中的Id
作为外键约束。这是有道理的,因为在成为学生或员工之前,您必须是用户。
最后,让我们为USERS
添加一些员工数据:
Phill
这很多,但现在你将开始获益。以上所有内容都是基础的,因为它提供了一种完全规范化的数据库布局方法,具有额外的灵活性,而且不需要 NULLABLE 外键。
在此实例中检索数据非常简单,我们甚至不必知道INSERT INTO EMPLOYEES(EmployeeId,EmployeeType)
VALUES(1,"Faculty");
是员工还是学生。我们来看一个示例查询:
Phill
返回:
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";
<强>结论:强>
直播示例:sqlfiddle
所以你有它。通过在+--------+--------+-------------+-----------+-----------+--------+------------+--------------+
| UserId | Name | Email | UserType | StudentId | Year | EmployeeId | EmployeeType |
+--------+--------+-------------+-----------+-----------+--------+------------+--------------+
| 1 | phill | ph@lms.com | Employee | (null) | (null) | 1 | Faculty |
+--------+--------+-------------+-----------+-----------+--------+------------+--------------+
,LEFT JOIN
和STUDENTS
表之间执行EMPLOYEES
,您将撤回两个表中任何一个中存在的所有值以及所有默认用户值。从这里开始,检查USERS
或NULL
上的StudentId
以确定您正在使用的用户类型非常简单。