#1452 - 无法添加或更新子行:外键约束失败

时间:2016-08-11 17:43:34

标签: mysql

我正在尝试将一些数据插入到表User中。 User表有2个外键:StudentIDStaffID

我希望能够输入应该链接到相关表格的StaffIDStudentID(已经有StudentIDStaffID)。表格User只能有StaffIDStudentID。任何人都可以帮忙吗?

INSERT INTO `User` (`UserName`, `Email`, `StudentID`,`StaffID`,`Paasword`) 
VALUES ('phill', 'ph@lms.com', '', '2201','654321');

1 个答案:

答案 0 :(得分:2)

好的,所以要做好准备。这个答案很长,但很彻底。

简答:

正如answer @HLGEM中所提到的那样,您可以通过在STAFFSTUDENT表中创建主键来完成您所要求的内容,大概是值{ {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。这种方法有两个好处:

  1. UserTypeIdUSERS是对UserTypeIdUSER_TYPES的外键引用,但不再必须是 NULLABLE
  2. 您可以拥有的用户类型多于UserTypeIdStudent
  3. 对于我们的案例研究,让我们创建两个用户类型StaffStudent(我将在这里解释为什么我没有使用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值为ENUMFacultyStaff。将此视为一般类型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 JOINSTUDENTS表之间执行EMPLOYEES,您将撤回两个表中任何一个中存在的所有值以及所有默认用户值。从这里开始,检查USERSNULL上的StudentId以确定您正在使用的用户类型非常简单。