82

我只是认为答案是错误的,因为外键没有uniqueness属性。

但是也有人说可以在自己加入表的情况下。我是新手SQL。如果它是真的,请解释如何以及为什么?

Employee table
| e_id | e_name  | e_sala  |  d_id  |
|----  |-------  |-----    |--------|
|  1   |   Tom   |  50K    |    A   |
|  2   | Billy   |  15K    |    A   |
|  3   | Bucky   |  15K    |    B   |


department table
| d_id | d_name  |
|----  |-------  |
|  A   |   XXX   | 
|  B   |   YYY   | 

现在, d_id 是外键,所以它如何成为主键。并解释一些关于join. 它的用途是什么?

4

7 回答 7

104

我认为这个问题有点令人困惑。

如果您的意思是“外键可以'引用'同一张表中的主键吗?”,答案是肯定的,正如一些人回答的那样。例如,在员工表中,员工的一行可能有一个用于存储经理的员工编号的列,其中经理也是员工,因此表中的一行与任何其他员工的行一样。

如果您的意思是“列(或列集)可以是同一个表中的主键和外键吗?”,在我看来,答案是否定的;似乎毫无意义。但是,以下定义在 SQL Server 中成功!

create table t1(c1 int not null primary key foreign key references t1(c1))

但我认为除非有人想出一个实际的例子,否则有这样的限制是没有意义的。

AmanS,在您的示例中,d_id 在任何情况下都不能成为 Employee 表中的主键。一张表只能有一个主键。我希望这能消除你的疑问。d_id 是/只能是部门表中的主键。

于 2013-09-08T06:06:21.850 回答
21

这可能是一个很好的解释示例

CREATE TABLE employees (
id INTEGER NOT NULL PRIMARY KEY,
managerId INTEGER REFERENCES employees(id), 
name VARCHAR(30) NOT NULL
);

INSERT INTO employees(id, managerId, name) VALUES(1, NULL, 'John');
INSERT INTO employees(id, managerId, name) VALUES(2, 1, 'Mike');

-- 解释: -- 在这个例子中。-- John 是 Mike 的经理。迈克不管理任何人。-- Mike 是唯一一个不管理任何人的员工。

于 2019-07-08T08:05:15.457 回答
17

当然,为什么不呢?假设您有一个Person表,其中包含idnameageparent_id,其中parent_id是同一个表的外键。您不需要将Person表格标准化为ParentChild表格,那将是矫枉过正。

Person
| id |  name | age | parent_id |
|----|-------|-----|-----------|
|  1 |   Tom |  50 |      null |
|  2 | Billy |  15 |         1 |

像这样的东西。

parent_id我想为了保持一致性,尽管如此,至少需要有 1 个空值。一个“阿尔法男性”行。

编辑:正如评论所示,Sam 找到了不这样做的充分理由。似乎在 MySQL 中,当您尝试对主键进行编辑时,即使您指定CASCADE ON UPDATE它也不会正确传播编辑。尽管主键(通常)在生产环境中禁止编辑,但它仍然是一个不容忽视的限制。因此,我将答案更改为:-您可能应该避免这种做法,除非您对生产系统有非常严格的控制(并且可以保证没有人会实施编辑 PK 的控制)。我没有在 MySQL 之外测试过它。

于 2013-09-08T05:26:59.770 回答
9

例如:类别的n个子类别级别。下表主键id由外键sub_category_id引用

在此处输入图像描述

于 2017-06-28T06:47:41.017 回答
2

使用同一个表中其他行的 id 作为外键的一个很好的例子是嵌套列表。

删除具有子代(即,行,引用父 ID),也有子代(即,引用子代 ID)的行将删除级联的行。

这将节省很多痛苦(以及很多关于如何处理孤儿的代码 - 即,引用不存在的 id 的行)。

于 2018-02-09T09:38:47.263 回答
0

在@mysagar 的答案中添加了在 MySQL 中执行相同操作的方法如下所示 -

CREATE TABLE t1 (
    -> c1 INT NOT NULL,
    -> PRIMARY KEY (c1),
    -> CONSTRAINT fk FOREIGN KEY (c1)
    -> REFERENCES t1 (c1)
    -> ON UPDATE RESTRICT
    -> ON DELETE RESTRICT
    -> );

会出错-

ERROR 1822 (HY000): Failed to add the foreign key constraint. Missing index for constraint 'fk' in the referenced table 't1'

正确的做法是——

CREATE TABLE t1 (
    -> c1 INT NOT NULL,
    -> PRIMARY KEY (c1),
    -> KEY i (c1),
    -> CONSTRAINT fk FOREIGN KEY (c1)
    -> REFERENCES t1 (c1)
    -> ON UPDATE RESTRICT
    -> ON DELETE RESTRICT
    -> );

我能想到的一个实用工具是快速修复,以确保在 中输入值后PRIMARY KEY column,它既不能更新,也不能删除。

例如,在这里让我们填充表格t1-

INSERT INTO t1 (c1) VALUES
    -> (1),
    -> (2),
    -> (3),
    -> (4),
    -> (5);
SELECT * FROM t1;
+----+
| c1 |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
+----+

现在,让我们尝试更新row1-

UPDATE t1
    -> SET c1 = 6 WHERE c1 = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`constraints`.`t1`, CONSTRAINT `fk` FOREIGN KEY (`c1`) REFERENCES `t1` (`c1`) ON DELETE RESTRICT ON UPDATE RESTRICT)

现在,让我们尝试删除row1-

DELETE FROM t1
    -> WHERE c1 = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`constraints`.`t1`, CONSTRAINT `fk` FOREIGN KEY (`c1`) REFERENCES `t1` (`c1`) ON DELETE RESTRICT ON UPDATE RESTRICT)
于 2021-09-16T12:02:45.450 回答
0

其他答案已经给出了足够清楚的例子,说明一条记录引用了同一张表中的另一条记录。

对于在同一个表中引用自身的记录,甚至还有有效的用例。例如,一个接受许多投标的销售点系统可能需要知道当付款不是销售的确切价值时使用哪个投标来进行更改。对于许多相同标书的标书,对于其他为国内现金的标书,对于其他标书,不允许进行任何形式的更改。

所有这一切都可以用一个单一的属性非常优雅地表示,该属性是一个引用同一表的主键的外键,并且其值有时与同一记录的相应主键匹配。在此示例中,可能需要缺少值(也称为 NULL 值)来表示不相关的含义:此标书只能以其全值使用。

流行的关系数据库管理系统顺利地支持这个用例。

外卖:

  1. 插入记录时,会验证外键引用是否存在插入之后,而不是插入之前。

  2. 使用单个语句插入多条记录时,插入记录的顺序很重要。分别检查每条记录的约束。

  3. 某些其他数据模式,例如那些涉及通过两个或多个表的记录级别的循环依赖的数据模式,根本不能完全插入,或者至少不能启用所有外键,它们必须使用插入的组合来建立和更新(如果确实有必要)。

于 2021-01-21T11:18:15.917 回答