外键可以引用同一表中的主键吗?


73

我只是认为答案是错误的,因为外键没有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。它有什么用?


您可能想要添加正在使用的DBMS,以便获得适用于DBMS的示例。
a_horse_with_no_name

Answers:


93

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

如果您的意思是“外键可以“引用”同一张表中的主键吗?”,答案是肯定的。例如,在雇员表中,雇员的行可能具有用于存储经理的雇员编号的列,其中经理也是雇员,因此表中的行将与其他雇员的行一样。

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

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

但是我认为,除非有人提出实际的例子,否则具有这样的约束是没有意义的。

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


我很清楚d_id是部门表的主键。员工表中的d_id也是外键。并且您还提到d_id可以是同一表(员工)中的主键。我的老师告诉我,如果员工桌自动加入,这是可能的。这一点我不清楚吗?
AmanS 2013年

1
@AmanS,您说过“您提到d_id可以是同一表(员工)中的主键”。但我没有; 这是我的语句“ AmanS,在您的示例中d_id在任何情况下都不能成为Employee表中的主键”。希望你能明白。即使在自连接情况下也是不可能的。表中的另一列可以引用同一表的主键。例如创建表employee(e_id int主键,e_name varchar(30),e_mgr int,外键(e_mgr)引用employee(e_id))。这是自连接的情况,e_mgr是引用主键e_id的外键。
mvsagar 2013年

您能告诉我任何实际的查询示例,其中外键可以引用主键吗?但是下面的人(ryvantage)也说可以。...我很困惑,请帮忙
AmanS 2013年

@AmanS,我在前面的评论中已经给出了一个employee表的示例,而ryvantage也给出了一个包含数据的Person表的示例。这些是实际的例子。您阅读了有关数据库系统的任何书籍,并再次阅读了这些注释,希望您能理解。没有什么比外键引用查询(DML语句)中的主键更重要了。该引用仅存在于DDL语句CREATE TABLE或ALTER TABLE语句中。我前面的注释中的DDL语句CREATE TABLE员工...显示了它。
mvsagar 2013年

2
@AmanS,这可能是您想要的。选择语句“ SELECT DISTINCT e.e_id AS'经理ID',e_ename AS'经理名称'来自雇员e,雇员m WHERE e.e_id = m.e_mgr;” 给您所有作为经理的员工。在此,将主键列e_id与外键列e_mgr进行比较。
mvsagar 2013年

17

当然可以,为什么不呢?比方说,你有一个Person表,其中idnameage,和parent_id,其中parent_id是一个外键相同的表。您不需要将Person表格标准化为ParentChild表格,那会太过分了。

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

这样的事情。

我想保持一致性,但是至少需要有1个null值parent_id。一“ alpha male”行。

编辑:如评论所示,萨姆找到了不这样做的充分理由。在MySQL中,即使您指定对主键进行编辑,也似乎CASCADE ON UPDATE无法正确传播该编辑。尽管主键(通常)是生产中编辑的禁区,但它是不可忽略的限制。因此,我将答案更改为:-除非您对生产系统有相当严格的控制(并且可以保证没有人会实施用于编辑PK的控件),否则您应该避免这种做法。我还没有在MySQL之外进行测试。


请看我用示例编辑的问题。你的答案仍然是吗?
AmanS 2013年

1
它不适用于update。检查sqlfiddle.com/#!9/445052/1/0然后尝试加入Update menus set id = 6 WHERE id = 1;您将获得#1451 - Cannot delete or update a parent row
山姆

@Sam有两件事:1)我看到它不起作用,但是我不同意它应该失败。对于级联更新,似乎没有任何逻辑上的原因导致更新失败。2)谁在实际情况下更改PK?寻求麻烦的
人大声笑

@ryvantage完全同意您的观点,在实际情况下PK不更新。只想添加此评论一提的是这是一个已知的文件限制(或错误在MySQL)。
山姆

我看到ON UPDATE CASCADE在编辑中提到了。我不建议[ON UPDATE CASCADE] [ON DELETE CASCADE]一般使用,因为级联操作不会触发触发器。如果您具有应在表A中进行更新的触发器,并且在表B中进行了导致A的级联更改的更新,则不会触发表A的触发器。请ON UPDATE RESTRICT改用,并在应用程序逻辑中手动处理必要的删除。
阿德里安·维克

13

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

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');

-说明:-在此示例中。约翰是麦克的经理。迈克没有管理任何人。-Mike是唯一不管理任何人的员工。


8

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

在此处输入图片说明


1

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

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

这将省去很多麻烦(以及处理与孤儿有关的大量代码(即,行,它们引用不存在的id))。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.