外键限制

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 列时验证 IdHotel_Id 值是否相同。并且由于您有某种循环引用(Staff 通过 Hotel_Id 引用 Hotel table,Hotel 引用 Staff table 通过 Manager_Id) 您必须 运行 ALTER TABLE 语句来添加额外的列 Manager_IdHotel_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.

您必须为 INSERTUPDATE 查询添加触发器(参见 等问题)才能进行检查。

以下示例查询显示了外键的工作原理:

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`))