好吧,準備好自己吧。這個答案很長,但徹底。
答案很簡單:
正如@HLGEM在此answer引用你可以完成你正在通過使主鍵在STAFF
和STUDENT
表,想必值StaffID
和StudentID
NULLABLE問。以下是他的回答中的相關片段:
要允許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;
注意在這個新的模式,我們不再需要StudentID
或StaffID
參考,而是我們有一個UserTypeId
。有兩個好處,這種做法:
USERS
。 UserTypeId
是USER_TYPES
的外鍵參考。 UserTypeId
,但不再必須是NULLABLE。
- 您可以擁有的用戶類型不僅僅是
Student
或Staff
。
對於我們的案例研究在這裏,讓我們創建兩個用戶類型Student
和Employee
(我爲什麼我不是在一個小的使用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
,Staff
或Administrative
的ENUM
值進一步定義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
,EMPLOYEES
和USERS
表之間執行LEFT JOIN
,您將撤回兩個表中的所有值以及所有默認用戶值。從這裏開始,您可以通過StudentId
或EmployeeId
來檢查NULL
,以確定您正在使用哪種用戶類型。
用戶表的限制是什麼?如果StudentID和StaffID都是外鍵並且都是必需的,那麼您將無法離開一個或另一個空 –
就是這樣!約束條件是UserID是PK,StaffID和StudentID是FK。 – user6195207
我不希望StudentID和StaffID都是必需的,只需要一個或另一個。 – user6195207