外键限制
Foreign key restrictions
我有两个 table 说,有主键的酒店 Hotel_ID
和有主键的员工 Staff_ID
。
酒店 table 还有另一列,Manager_ID
引用了 Staff_ID
的员工。
工作人员 table 使用其列 H_ID
引用 Hotel_ID 以指示工作人员在哪家酒店工作。
我一直在试图弄清楚是否可以限制 Manager_ID
的允许值,以便只有同一家酒店的员工才能成为经理。
我知道这里有一个交叉引用,但我的理解是这应该不是问题。有人能告诉我如何将其合并到酒店 table 的创建语句中吗?
您可以在 staff
table 中创建标记或 role
列,以表明此人是经理还是在酒店中担任特定角色。您将不再需要 hotel
table 中的 Manager_Id
列。 table 可能如下所示:
Hotel
- Id
- Name
Staff
- Id
- Hotel_Id
- IsManager
- Firstname
- Lastname
当您添加新内容时,您可以设置 IsManager
标志以表明此人是酒店的经理,由 Hotel_Id
列中的 ID 标识。
您可以将多列外键添加到 select,不仅是员工的 ID,还可以是 hotel
table 中分配的 hotel_id
。这将导致看起来很奇怪的 table 结构,如下所示:
Hotel
- Id
- Name
- Manager_Id
- Hotel_Id
Staff
- Id
- Hotel_Id
- IsManager
- Firstname
- Lastname
这看起来特别奇怪,因为您在 Hotel
table 中有两次相同的 ID。为了使其正常工作,您必须添加触发器以在使用 Hotel_Id
列时验证 Id
和 Hotel_Id
值是否相同。并且由于您有某种循环引用(Staff
通过 Hotel_Id
引用 Hotel
table,Hotel
引用 Staff
table 通过 Manager_Id
) 您必须 运行 ALTER TABLE
语句来添加额外的列 Manager_Id
和 Hotel_Id
。查询可能如下所示:
CREATE TABLE Hotel
(
Id INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(30)
);
CREATE TABLE Staff
(
Id INT AUTO_INCREMENT PRIMARY KEY,
Hotel_Id INT NOT NULL,
FirstName VARCHAR(30),
LastName VARCHAR(30),
FOREIGN KEY (Hotel_Id) REFERENCES Hotel(Id),
INDEX (Id, Hotel_Id)
);
第二个索引用于Hotel
中的外键 table:
ALTER TABLE Hotel ADD Manager_ID INT NULL;
ALTER TABLE Hotel ADD Hotel_ID INT NULL;
ALTER TABLE Hotel ADD FOREIGN KEY (Manager_ID, Hotel_ID) REFERENCES Staff(Id, Hotel_Id);
遗憾的是,您不能对 Id
列的值使用 CHECK CONSTRAINT
。如果可以的话,可以这样写:
ALTER TABLE Hotel ADD CONSTRAINT CHK_Hotel CHECK (Hotel_ID = Id OR Hotel_Id IS NULL);
这将验证 Hotel_Id
列(其值来自 Staff
table)必须与 Id
列相同。但是,您将收到以下错误消息:
Check constraint 'CHK_Hotel' cannot refer to an auto-increment column.
您必须为 INSERT
和 UPDATE
查询添加触发器(参见 等问题)才能进行检查。
以下示例查询显示了外键的工作原理:
INSERT INTO Hotel (Name) VALUES ('Some Hotel Name');
SELECT * FROM Hotel;
+----+-----------------+------------+----------+
| Id | Name | Manager_ID | Hotel_ID |
+----+-----------------+------------+----------+
| 1 | Some Hotel Name | NULL | NULL |
+----+-----------------+------------+----------+
INSERT INTO Staff (Hotel_Id, FirstName, LastName) VALUES (1, 'John', 'Doe');
SELECT * FROM Staff;
+----+----------+-----------+----------+
| Id | Hotel_Id | FirstName | LastName |
+----+----------+-----------+----------+
| 1 | 1 | John | Doe |
+----+----------+-----------+----------+
UPDATE Hotel SET Manager_Id = 1, Hotel_Id = 1 WHERE Id = 1;
SELECT * FROM Hotel;
+----+-----------------+------------+----------+
| Id | Name | Manager_ID | Hotel_ID |
+----+-----------------+------------+----------+
| 1 | Some Hotel Name | 1 | 1 |
+----+-----------------+------------+----------+
UPDATE Hotel SET Manager_Id = 1, Hotel_Id = 2 WHERE Id = 1;
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`Hotel`, CONSTRAINT `Hotel_ibfk_1` FOREIGN KEY (`Manager_ID`, `Hotel_ID`) REFERENCES `Staff` (`Id`, `Hotel_Id`))
我有两个 table 说,有主键的酒店 Hotel_ID
和有主键的员工 Staff_ID
。
酒店 table 还有另一列,Manager_ID
引用了 Staff_ID
的员工。
工作人员 table 使用其列 H_ID
引用 Hotel_ID 以指示工作人员在哪家酒店工作。
我一直在试图弄清楚是否可以限制 Manager_ID
的允许值,以便只有同一家酒店的员工才能成为经理。
我知道这里有一个交叉引用,但我的理解是这应该不是问题。有人能告诉我如何将其合并到酒店 table 的创建语句中吗?
您可以在 staff
table 中创建标记或 role
列,以表明此人是经理还是在酒店中担任特定角色。您将不再需要 hotel
table 中的 Manager_Id
列。 table 可能如下所示:
Hotel
- Id
- Name
Staff
- Id
- Hotel_Id
- IsManager
- Firstname
- Lastname
当您添加新内容时,您可以设置 IsManager
标志以表明此人是酒店的经理,由 Hotel_Id
列中的 ID 标识。
您可以将多列外键添加到 select,不仅是员工的 ID,还可以是 hotel
table 中分配的 hotel_id
。这将导致看起来很奇怪的 table 结构,如下所示:
Hotel
- Id
- Name
- Manager_Id
- Hotel_Id
Staff
- Id
- Hotel_Id
- IsManager
- Firstname
- Lastname
这看起来特别奇怪,因为您在 Hotel
table 中有两次相同的 ID。为了使其正常工作,您必须添加触发器以在使用 Hotel_Id
列时验证 Id
和 Hotel_Id
值是否相同。并且由于您有某种循环引用(Staff
通过 Hotel_Id
引用 Hotel
table,Hotel
引用 Staff
table 通过 Manager_Id
) 您必须 运行 ALTER TABLE
语句来添加额外的列 Manager_Id
和 Hotel_Id
。查询可能如下所示:
CREATE TABLE Hotel
(
Id INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(30)
);
CREATE TABLE Staff
(
Id INT AUTO_INCREMENT PRIMARY KEY,
Hotel_Id INT NOT NULL,
FirstName VARCHAR(30),
LastName VARCHAR(30),
FOREIGN KEY (Hotel_Id) REFERENCES Hotel(Id),
INDEX (Id, Hotel_Id)
);
第二个索引用于Hotel
中的外键 table:
ALTER TABLE Hotel ADD Manager_ID INT NULL;
ALTER TABLE Hotel ADD Hotel_ID INT NULL;
ALTER TABLE Hotel ADD FOREIGN KEY (Manager_ID, Hotel_ID) REFERENCES Staff(Id, Hotel_Id);
遗憾的是,您不能对 Id
列的值使用 CHECK CONSTRAINT
。如果可以的话,可以这样写:
ALTER TABLE Hotel ADD CONSTRAINT CHK_Hotel CHECK (Hotel_ID = Id OR Hotel_Id IS NULL);
这将验证 Hotel_Id
列(其值来自 Staff
table)必须与 Id
列相同。但是,您将收到以下错误消息:
Check constraint 'CHK_Hotel' cannot refer to an auto-increment column.
您必须为 INSERT
和 UPDATE
查询添加触发器(参见
以下示例查询显示了外键的工作原理:
INSERT INTO Hotel (Name) VALUES ('Some Hotel Name');
SELECT * FROM Hotel;
+----+-----------------+------------+----------+
| Id | Name | Manager_ID | Hotel_ID |
+----+-----------------+------------+----------+
| 1 | Some Hotel Name | NULL | NULL |
+----+-----------------+------------+----------+
INSERT INTO Staff (Hotel_Id, FirstName, LastName) VALUES (1, 'John', 'Doe');
SELECT * FROM Staff;
+----+----------+-----------+----------+
| Id | Hotel_Id | FirstName | LastName |
+----+----------+-----------+----------+
| 1 | 1 | John | Doe |
+----+----------+-----------+----------+
UPDATE Hotel SET Manager_Id = 1, Hotel_Id = 1 WHERE Id = 1;
SELECT * FROM Hotel;
+----+-----------------+------------+----------+
| Id | Name | Manager_ID | Hotel_ID |
+----+-----------------+------------+----------+
| 1 | Some Hotel Name | 1 | 1 |
+----+-----------------+------------+----------+
UPDATE Hotel SET Manager_Id = 1, Hotel_Id = 2 WHERE Id = 1;
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`Hotel`, CONSTRAINT `Hotel_ibfk_1` FOREIGN KEY (`Manager_ID`, `Hotel_ID`) REFERENCES `Staff` (`Id`, `Hotel_Id`))