2016-08-11 160 views
0

我試圖插入一些數據到表UserUser表有2個外鍵:StudentIDStaffID#1452 - 無法添加或更新子行:外鍵約束失敗

我希望能夠輸入StaffIDStudentID,該鏈接應該鏈接到相關表格(已經有StudentIDStaffID)。表User只能有StaffIDStudentID。誰可以幫忙?

INSERT INTO `User` (`UserName`, `Email`, `StudentID`,`StaffID`,`Paasword`) 
VALUES ('phill', '[email protected]', '', '2201','654321'); 
+0

用戶表的限制是什麼?如果StudentID和StaffID都是外鍵並且都是必需的,那麼您將無法離開一個或另一個空 –

+0

就是這樣!約束條件是UserID是PK,StaffID和StudentID是FK。 – user6195207

+0

我不希望StudentID和StaffID都是必需的,只需要一個或另一個。 – user6195207

回答

2

好吧,準備好自己吧。這個答案很長,但徹底。

答案很簡單:

正如@HLGEM在此answer引用你可以完成你正在通過使主鍵在STAFFSTUDENT表,想必值StaffIDStudentIDNULLABLE問。以下是他的回答中的相關片段:

要允許FK中的空值,通常您只需在具有FK的字段上允許空值。空值與作爲FK的想法是分開的。

爲此,您可以在您的表定義添加NULL到您指定創建一個類似於下面的語句:

CREATE TABLE STUDENT (
    StudentID INT UNSIGNED NULL PRIMARY KEY AUTO_INCREMENT 
    ... 
) 

以上是如何將其應用到STUDENT表的例子。 STAFF表格也會有類似的方法。請注意,在配置ID字段時,基於常規配置的常見配置會提供額外的值作爲建議。

龍答:

由於@HLGEM在他的回答中提到,有一些時候是適當的有一個外鍵約束,可以是NULL。但是,就你而言,它建議數據沒有完全標準化。在你的情況下,需要一個NULL外鍵可以消除一個小表重構。讓設計數據庫表時的探索另一種可能性:

案例研究:

讓我們用下面的假設開始。因爲你在你的問題中提到:

我希望能夠輸入應該鏈接到相關表格(已經有StudentID或StaffID)的StaffID或StudentID。該表用戶只能有,STAFFID或StudentID

這可能是一個安全的假設說,一個用戶必須是一個工作人員一個學生兩。這個假設爲擁有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; 

注意在這個新的模式,我們不再需要StudentIDStaffID參考,而是我們有一個UserTypeId。有兩個好處,這種做法:

  1. USERSUserTypeIdUSER_TYPES的外鍵參考。 UserTypeId,但不再必須是NULLABLE
  2. 您可以擁有的用戶類型不僅僅是StudentStaff

對於我們的案例研究在這裏,讓我們創建兩個用戶類型StudentEmployee(我爲什麼我不是在一個小的使用Staff在這裏解釋)。讓我們繼續前進,並使用Phill的初始值填充USERS表,您的員工是您在問題中提到的。

INSERT INTO USER_TYPES(UserType) 
VALUES("Employee"),("Student"); 

INSERT INTO USERS(Name,Email,Password,UserTypeId) 
VALUES("phill","[email protected]","654321",1); 

非常好!我們的新設計快速融合在一起。現在讓我們創建另外兩個表,一個叫STUDENTS,另一個叫EMPLOYEES。在這種情況下,我選擇EMPLOYEES而不是STAFF,因爲它可以讓您更靈活地定義員工。正如您在定義中所看到的,您可以使用Faculty,StaffAdministrativeENUM值進一步定義Employee的用戶類型。把它看作一般類型的子類型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列,而是從USERS表引用Id的外鍵約束。這是有道理的,因爲您必須是用戶,然後才能成爲學生員工

最後,讓我們添加一些員工數據Phill

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 = "[email protected]"; 

返回:

+--------+--------+-------------+-----------+-----------+--------+------------+--------------+ 
| UserId | Name | Email  | UserType | StudentId | Year | EmployeeId | EmployeeType | 
+--------+--------+-------------+-----------+-----------+--------+------------+--------------+ 
|  1 | phill | [email protected] | Employee | (null) | (null) |   1 | Faculty  | 
+--------+--------+-------------+-----------+-----------+--------+------------+--------------+ 

結論:

活生生的例子:sqlfiddle

所以你有它。通過在STUDENTS,EMPLOYEESUSERS表之間執行LEFT JOIN,您將撤回兩個表中的所有值以及所有默認用戶值。從這裏開始,您可以通過StudentIdEmployeeId來檢查NULL,以確定您正在使用哪種用戶類型。

+0

非常感謝你@ War10ck!這是一個很好的迴應。我能夠輕鬆探索基礎知識。 :) – user6195207

相關問題