【问题标题】:Can a foreign key refer to the primary key of its own table?外键可以引用自己表的主键吗?
【发布时间】:2014-08-07 20:49:35
【问题描述】:

我正在为工作创建一个 MySQL 员工数据库,我希望它存储员工的主管。

假设我有一个名为“employee”的表,其中包含“id”、“first_name”、“last_name”和“supv_id”字段,其中“id”是主键,“supv_id”是指外键和员工身份证。

目前,我将“supv_id”作为指向单独表“主管”的外键。该表仅由指向员工表的“id”和“empl_id”组成。但是,如果有一种方法可以简单地将 'employee' 中的 'supv_id' 指向 'employee.id',这将完全不需要我的 'supervisor' 表。这是一个例子:

+----+--------+-----------+---------+
| id | f_name | l_name    | supv_id |
+----+--------+-----------+---------+ 
|  1 | Han    | Solo      |    NULL | //Or 0?
|  2 | Luke   | Skywalker |       1 |
+----+--------+-----------+---------+

简而言之,我希望 'suppv_id' 指向另一位员工。这有意义吗?我该怎么做呢?

谢谢!

编辑:固定表

【问题讨论】:

  • 外键可以引用mysql中任何数据库(或其他dbs中的schema)中任何用户表(包括自身,包括复合键)中的任何唯一键或主键
  • NULL 是正确的值,如果没有匹配。如果您尝试插入零 (0),则结果将违反外键,因为没有值为 0 的 id。
  • 根据答案,这是描述关系数据库中层次结构的最简单解决方案,但是查询任意级别的节点变得困难。您可能想看看其他一些数据模型,并考虑在提交此模型之前您将如何访问数据。
  • @symcbean 你有点过头了!这一切对我来说还是很新鲜的。目前我正在研究模型和设计,最终我还将创建一个便于查询的界面。它仍处于早期阶段,因此如果您有任何建议,我愿意接受。谢谢!
  • @VMai 感谢您的确认 :)

标签: mysql database relational-database


【解决方案1】:

您可以创建如下表:

CREATE TABLE laya2 (
    id INT NOT NULL PRIMARY KEY,
    f_name VARCHAR(20),
    l_name VARCHAR(20),
    supv_id INT,
    INDEX supv_id_idx (supv_id),
    FOREIGN KEY (supv_id)
        REFERENCES laya2(id) 
        ON DELETE SET NULL      -- example for an action
) ENGINE=INNODB;

我的示例将引用选项设置为 SET NULL,因为我认为这是合乎逻辑的选项。如果一个监督别人的员工离开了,那么这些员工首先没有主管。另一种选择是使用NO ACTION,因为您可以轻松识别没有有效主管的员工并为他们找到新主管。 ON DELETE CASCADE 在这里是错误的,因为那些员工不会同时离开......

你可以插入员工

INSERT INTO laya2 VALUES
(1, 'Han', 'Solo', NULL),
(2, 'Luke', 'Skywalker', 1);

(两次成功插入),但没有

INSERT INTO laya2 VALUES
(3, 'Anakin', 'Skywalker', 0);

此语句将失败,因为外键约束失败。

删除 Han Solo 会将 Luke Skywalker 的 supv_id 更改为 NULL,因为引用选项 ON DELETE SET NULL

DELETE FROM laya2 WHERE id = 1;    -- this will set the supv_id for Luke Skywalker to NULL

【讨论】:

  • 好的,有道理,非常感谢!但是,我认为您的第二个选项(不采取行动)更好,因为我的员工属于具有不同主管的不同组,因此我希望将它们分开以便于更新,而不是主管设置为 NULL 的混合员工集。谢谢你:)
【解决方案2】:

是的,将表连接到自身。这是多种方法之一:

SELECT a.l_name AS employee, b.l_name AS supervisor 
  FROM employee AS a, employee AS b 
  WHERE a.supv_id = b.id             -- link tables
    AND a.id = 2                     -- get employee

返回:

employee  | supervisor
----------+-----------
Skywalker | Solo

【讨论】:

  • 谢谢,这很有用:)
  • 嗯,似乎有问题。我按照你说的尝试了这个并得到了正确的输出。然而,在将 a.supv_id=b.id 切换到 b.supv_id=a.id 时,输出显示 Han Solo 的主管是 Luke Skywalker。如果 Han Solo 没有主管(即supv_id=NULL),这怎么可能?
  • 当您将其更改为b.supv_id = a.id 时,您将“b”表更改为员工表,将“a”表更改为主管表,因此您还需要更改选择列部分。
【解决方案3】:

是的,你可以定义一个外键来引用它自己的表的主键。

create table employee (id int(10),
                       f_name varchar(10),
                       l_name varchar(10),
                       supv_id int(10)) ENGINE=InnoDB;
alter table employee add primary key (id);
alter table employee add foreign key (supv_id) references employee (id);

没有主管的员工必须在 supv_id 列中为 NULL。

【讨论】:

    猜你喜欢
    • 2013-09-11
    • 2021-09-06
    • 1970-01-01
    • 2013-07-12
    • 2012-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多