您误解了外键是什么。它们并不是将数据添加到多个表的神奇方式。它们是约束。它们限制了可以出现在access_codes.id_fk 列中的值。在这种情况下,唯一允许的值是出现在codes.id 列中的值。但是每次在codes 中插入新行时,不会在access_codes 中插入新行。你必须自己做。
附带说明 - 在这种情况下,将所有数据保存在一个表中不是更简单吗?
添加:数据库键速成课程
让我们从主键开始,它很有帮助。当今大多数 RDBMS 都将表视为大行。这些行没有排序(每次您执行select * from mytable 时,您可能会以不同的顺序将它们返回),并且没有什么可以将它们区分开来。就像你将 100 个绿球扔进一个桶里,你将无法分辨哪个球是哪个。如果你想把它们区分开来,你需要给每个球一些独特的标记,比如在每个球上写一个不同的数字或其他东西。
在使用数据库时,我们通常希望将行区分开来。每当我们对表做某事时,我们通常想要更新或删除其中的特定行,因此我们需要那个唯一的识别标记。数据库引擎制造商意识到了这一点,并且现在大多数 RDBMS 都提供了两个重要的特性 - 主键和 auto_increment 列(尽管这些特性的名称可以从 DB 到 DB)。
当您将一列标记为“主键”列时,这意味着该列将包含每一行的唯一 ID。数据库引擎将不允许您在主键列中插入具有相同值的两行(或更新一行以使其如此),因为此列的目的是唯一标识每一行.具有相同 ID 的两行会破坏此目的。
请注意,您还可以将多列作为主键。在这种情况下,每一列的值不需要唯一,但每一行的值组合在表的所有行中必须是唯一的。
此外,如果需要,您还可以拥有其他“唯一”列 - 甚至还有一个“唯一索引”,它再次使数据库拒绝插入具有非唯一值的行。
但是主键是特殊的。首先是因为它告诉任何查看该表的人“这是区分这些行的官方方式”,其次是因为大多数 RDBMS 实际上以与主键相同的顺序将行存储在磁盘上。这意味着如果您知道它的主键值,则查找一行非常快。
所以大多数人只是使用主键来识别行,而其他唯一索引很少被发现(尽管它们确实不时发生)。
Auto_increment 是一项有助于生成这些唯一 ID 的功能。如果将列(通常是整数/数字)标记为“auto_increment”(某些 RDBMS 只允许为每个表标记一列),那么在插入新行时,该列将自动获得一个比先前最大值大 1 的值在那张桌子上。唯一标识符变得容易。
现在介绍外键。
由于某种原因,我们需要将两行(通常在不同的表中,但偶尔在同一个表中)链接在一起也是很常见的。
例如 - 我们公司制作的软件与停车费有关。所以我们有一张表格,列出了当前停在某个地方的所有汽车。每行代表一辆停放的汽车。它包含车牌号,停车开始时,yadda yadda。然后我们有另一个表格,列出了我们所有的客户——用户名、密码哈希、电话号码、电子邮件和作品。每行代表一个客户。另一张表格列出了我们经营的所有停车场。每个停车场一排。名称、地址、GPS 坐标、描述、价格等
这些表中的每一个都有一个 auto_increment ID 列,这也是主键。
现在,在第一个表中 - 列出停放了哪些汽车的表 - 对于每辆车,我们还想知道哪个客户停放了它,以及停在哪个停车场。所以我们有两列 - client_id 和 lot_id。在client_id 列中,我们存储客户表的ID 的值,在lot_id 中存储手数表的值。
因此,例如,如果我们看到车牌为AB1234 的汽车停在了车上,属于ID 为222 的客户,那么我们可以转到clients 表,找到ID 为的行222 并看到它是 John Smith。同样,我们可以查找特定批次,因为我们知道它的 ID 值。
这就是外键的全部内容 - 它只是将一行的唯一 ID 放入另一行的想法,这样您就可以知道哪一行与哪一行相关(另外,这就是“关系”部分的来源来自“关系数据库”)。
现在,还有一件事要介绍 - 外键约束 - 这是 RDBMS 制造商提供的一个很棒的功能。您不是严格要求使用它,但我强烈建议您使用它。真是太好了。
基本上,它的作用是您可以告诉 RDBMS“此表中的该列实际上是该表中该列的外键”。然后数据库将帮助您确保一切都排好。
例如,如果客户表中没有 ID 为 222 的客户,我将无法为客户 222 插入停放的车辆。如果我尝试删除客户222,它不会允许我这样做,因为还有一辆车停在那里。换句话说,它确保无论我从停放的车辆表中选择哪一行,如果我从该行中获取客户端 ID,则客户端表中始终会有一行与此 ID 匹配。在地狱里我没有办法绕过它。这样可以避免很多麻烦。