在 SQL 中,当复合主键成为外键时应该如何被其它表引用

news/2024/10/18 7:46:45/

文章目录

  当研究一个问题慢慢深入时,一个看起来简单的问题也暗藏玄机。在 SQL 中,主键成为外键这是一个很平常的问题,乍一看没啥值得注意的。但如果这个主键是一种复合主键,而另一个表又引用这个键作为它的复合主键,问题就会变得复杂。

  这里为了便于说明,简单抽象出这样一个情景。数据库中有很多用户(User),每个用户有他的好友分组(Folder),每个分组下面有该用户的好友(Contact)。下面看看应该如何建表。

  • User 表建表示例代码如下:

    CREATE TABLE User (id VARCHAR(64) NOT NULL,name VARCHAR(64) NOT NULL,# ...为了简化说明,此表省略其它字段...PRIMARY KEY (id)
    );
  • Folder 表建表示例代码如下:

    CREATE TABLE Folder (id VARCHAR(64) NOT NULL,userId VARCHAR(64) NOT NULL,name VARCHAR(64) NOT NULL,# ...为了简化说明,此表省略其它字段...PRIMARY KEY (userId, id),# 因为上面的是复合主键,所以自动创建的是联合索引,而其它表的外键引用需要的是单个索引INDEX idIndex (id),FOREIGN KEY (userId) REFERENCES User (id)
    );
  • Contact 表建表示例代码如下:

    CREATE TABLE Contact (id VARCHAR(64) NOT NULL,# 表示此联系人属于谁的好友userId VARCHAR(64) NOT NULL,# 表示此联系人对应 User 中的 idlinkedUserId VARCHAR(64) NOT NULL,folderId VARCHAR(64) NOT NULL,# ...为了简化说明,此表省略其它字段...PRIMARY KEY (userId, id),# 因为上面的是复合主键,所以自动创建的是联合索引,而其它表的外键引用需要的是单个索引INDEX idIndex (id),# 同一个用户,不能拥有两个相同 ID 的 ContactUNIQUE (userId, linkedUserId),# 当复合主键成为外键时,必须整个复合主键一起作为外键,不能只引用复合主键其中的某个属性FOREIGN KEY (userId) REFERENCES Folder (userId),FOREIGN KEY (folderId) REFERENCES Folder (id),FOREIGN KEY (linkedUserId) REFERENCES User (id)
    );
    
  • 建表示意图如下:

    在这里插入图片描述

    在这里插入图片描述

  笔者已经将正确的建表在上述给出了,但问题其实不简单。注意看,表 Contact 引用了两个表的外键:表 User 和 表 Folder。而很奇妙的是,表 User、Folder 和 Contact 都有一个形同“userId”的字段,而且,它们的这个字段的意义是相同的。那么,表 Contact 中的 userId 究竟是引用表 User 中的 id 呢?还是引用表 Folder 中的 userId 呢?还是随便选一个都可以呢?

  答案是必须引用表 Folder 中的 userId,而不能引用表 User 中的 id。原因是,当复合主键成为外键时,必须整个复合主键一起作为外键,不能只引用复合主键其中的某个属性

  注意看,表 Contact 的属性 folderId 已经引用了表 Folder 的属性 id 了,但表 Folder 的主键是 (id,userId)。在这个情形下,表 Contact 必须也同时引用表 Folder 关于这个复合主键的其它属性。而正好表 Contact 有一个属性 userId,所以它必须引用表 Folder 中的 userId。

  可是,表 Contact 不是也和表 User 有引用啊,为什么没有受到表 User 的约束呢?因为 User 的主键不是复合主键,而且表 Contact 已经通过属性 linkedUserId 引用了表 User 的主键 id,因此不需要强制引用 User 的其它属性。

  当然,这只是 SQL 上的逻辑,而 SQL 只是一套标准,各个数据库的服务提供商对 SQL 的支持和实现因人而异。在 MySQL 中,如果建表时错误地将上述表 Contact 中的 userId 引用了表 User 中的 id,MySQL 并不会抛出错误,因为 MySQL 关于这方面不太严谨。但如果使用的是 SQLite,SQLite 将会在建表时就抛出错误。但不管各厂商的支持如何,将应该保证数据库建表的逻辑是正确的。


http://www.ppmy.cn/news/1215714.html

相关文章

[100天算法】-球会落何处(day 76)

题目描述 用一个大小为 m x n 的二维网格 grid 表示一个箱子。你有 n 颗球。箱子的顶部和底部都是开着的。箱子中的每个单元格都有一个对角线挡板,跨过单元格的两个角,可以将球导向左侧或者右侧。将球导向右侧的挡板跨过左上角和右下角,在网…

【Spring Boot】034-Spring Boot 整合 JUnit

【Spring Boot】034-Spring Boot 整合 JUnit 文章目录 【Spring Boot】034-Spring Boot 整合 JUnit一、单元测试1、什么是单元2、什么是单元测试3、为什么要单元测试 二、JUnit1、概述简介特点 2、JUnit4概述基本用法 3、JUnit5概述组成 4、JUnit5 与 JUnit4 的常用注解对比 三…

[100天算法】-不同路径 III(day 75)

题目描述 在二维网格 grid 上,有 4 种类型的方格:1 表示起始方格。且只有一个起始方格。 2 表示结束方格,且只有一个结束方格。 0 表示我们可以走过的空方格。 -1 表示我们无法跨越的障碍。 返回在四个方向(上、下、左、右&#…

海上船舶交通事故VR模拟体验低成本高效率-深圳华锐视点

在海上运输行业,安全事故的防范和应对能力是企业安全教育的重中之重。针对这一问题,海上运输事故VR模拟逃生演练成为了一种创新且高效的教育手段。通过这种演练,企业能够在提升员工安全意识和技能方面获得多方面的帮助。 在VR船舶搜救演练中&…

【C语言】深入解开指针(二)

🌈write in front :🔍个人主页 : 啊森要自信的主页 🌈作者寄语 🌈: 小菜鸟的力量不在于它的体型,而在于它内心的勇气和无限的潜能,只要你有决心,就没有什么事情是不可能的…

设计模式-备忘录模式(Memento)

设计模式-备忘录模式(Memento) 一、备忘录模式概述1.1 什么是备忘录模式1.2 简单实现备忘录模式1.3 使用备忘录模式的注意事项 二、备忘录模式的用途三、备忘录模式实现方式3.1 基于数组的备忘录实现方式3.2 基于集合的备忘录实现方式3.3 基于HashMap的备…

眼科动态图像处理系统使用说明(2023-8-11 ccc)

眼科动态图像处理系统使用说明 2023-8-11 ccc 动态眼科图像捕捉存贮分析与传输系统,是由计算机软件工程师和医学专家组结合,为满足医院临床工作的需要,在2000年开发的专门用于各类眼科图像自动化分析、处理和传输的软件系统。该系统可以和各…

拆位线段树 E. XOR on Segment

Problem - E - Codeforces 区间求和,区间异或的操作跟线段树的区间求和、区间相见相似,考虑用线段树。 发现数组初始值最多是1e6,有不到25位,可以知道异或最大值是这些位数全是1的情况。 发现可以对每一位进行运算就和。 我们开…