涉及多个表的外键约束

2023-11-22

我在 Postgres 9.3 数据库中有以下场景:

  • 表 B 和 C 参考表 A。
  • 表 C 有一个引用表 B 的可选字段。

我想确保对于表 C 中引用表 B 的每一行,c.b.a = c.a。也就是说,如果 C 引用了 B,则两行应指向表 A 中的同一行。

  • 我可以重构表 C,以便如果指定了 c.b,则 c.a 为 null,但这会使连接表 A 和 C 的查询变得尴尬。
  • 我也许还可以使表 B 的主键包含其对表 A 的引用,然后使表 C 的外键对表 B 包含表 C 对表 A 的引用,但我认为这种调整太尴尬了,无法证明其好处。
  • 我认为这可以通过在表 C 上插入/更新之前运行的触发器来完成,并拒绝违反指定约束的操作。

在这种情况下是否有更好的方法来强制数据完整性?


有一个非常简单、万无一失的解决方案。适用于 Postgres 9.3 - 当提出原始问题时。适用于当前的 Postgres 13 - 当添加赏金中的问题时:

希望了解是否可以在没有数据库触发器的情况下实现这一点

FOREIGN KEY限制条件可以跨越多列。只需将表 A 的 ID 包含在从表 C 到表 B 的 FK 约束中即可。这会强制 B 和 C 中的链接行始终指向 A 中的同一行。例如:

CREATE TABLE a (
  a_id int PRIMARY KEY
);

CREATE TABLE b (
  b_id int PRIMARY KEY
, a_id int NOT NULL REFERENCES a
, UNIQUE (a_id, b_id)  -- redundant, but required for FK
);

CREATE TABLE c (
  c_id int PRIMARY KEY
, a_id int NOT NULL REFERENCES a
, b_id int
, CONSTRAINT fk_simple_and_safe_solution
  FOREIGN KEY (a_id, b_id) REFERENCES b(a_id, b_id)  -- THIS !
);

最小样本数据:

INSERT INTO a(a_id) VALUES
  (1)
, (2);

INSERT INTO b(b_id, a_id) VALUES
  (1, 1)
, (2, 2);

INSERT INTO c(c_id, a_id, b_id) VALUES
  (1, 1, NULL)  -- allowed
, (2, 2, 2);    -- allowed

按要求不允许:

INSERT INTO c(c_id, a_id, b_id) VALUES (3,2,1);
ERROR:  insert or update on table "c" violates foreign key constraint "fk_simple_and_safe_solution"
DETAIL:  Key (a_id, b_id)=(2, 1) is not present in table "b".

数据库小提琴here

默认MATCH SIMPLEFK 约束的行为是这样的(引用手册):

MATCH SIMPLE允许任何外键列为空;如果其中任何一个为空,则该行不需要在引用的表中具有匹配项。

所以 NULL 值c(b_id)仍然允许(根据要求:“可选字段”)。对于这种特殊情况,FK 约束被“禁用”。

我们需要逻辑上的冗余UNIQUE约束于b(a_id, b_id)以允许 FK 引用它。但通过让它成为现实(a_id, b_id)代替(b_id, a_id),它本身也很有用,提供了有用的索引b(a_id)除其他外,还支持其他 FK 约束。看:

  • 复合索引也适合第一个字段的查询吗?

(附加索引c(a_id)因此通常很有用。)

进一步阅读:

  • MATCH FULL、MATCH SIMPLE 和 MATCH PARTIAL 之间的区别?
  • 强制执行“两张桌子之外”的约束
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

涉及多个表的外键约束 的相关文章

随机推荐

  • 在具有多列的material-ui表上添加水平滚动的方法是什么?

    我跟随这个表的例子对于 React Material UI 框架 我正在寻找一种可能性 当我有很多列时 使我的表格可以水平滚动 例如 我有许多列被挤压以适应页面宽度 因此它们的内容被缩短 我认为它在材料用户界面规范中通过链接进行了描述显示完
  • 突然禁止访问

    从今天早上开始 我们所有使用 DialogFlow 的 ChatBot 都被拒绝 响应代码为 403 和以下 JSON status code 401 errorType unauthorized errorDetails You are
  • OSX 上的 libxml2 和 libxml2-dev

    当尝试构建 Unix QuickFIX 引擎时 我在 bootstrap 之后收到以下错误 warning macro AM PATH XML2 not found in library 据我了解 libxml2 已经随 XCode OS
  • 在delphi中将十六进制字符串转换为十进制值

    我在使用 Delphi 将十六进制值的字符串表示形式转换为整数值时遇到问题 例如 FC75B6A9D025CB16 当我使用该功能时给我 802829546 Abs StrToInt64 FC75B6A9D025CB16 但如果我使用Win
  • 如何在线性时间内计算最小瓶颈生成树?

    利用克鲁斯卡尔算法 我们可以在最坏情况下以 O E log V 找到最小瓶颈生成树 这是因为每个最小生成树都是最小瓶颈生成树 但我被这个求职面试问题困住了this course 即使在最坏的情况下 我们如何在线性时间内找到最小瓶颈生成树 请
  • 错误 LNK1104:无法打开文件“Debug\MyProjectLib.lib”

    我有以下内容CMakeLists txt文件来生成我的基于Qt的项目 cmake minimum required VERSION 2 8 12 project MyProject find package Qt5Widgets set M
  • React-Style、Webpack、React - 未捕获错误:不变违规:`style` 属性

    我的浏览器中出现以下错误 未捕获的错误 不变违规 styleprop 期望从样式属性到值的映射 而不是字符串 例如 使用 JSX 时 style marginRight spaces em 这是运行 webpack dev server 并
  • 如何使用 Python 创建文件路径的 zip 文件(包括空目录)?

    我一直在尝试使用zipfile and shutil make archive递归创建目录的 zip 文件的模块 这两个模块都工作得很好 除了空目录不会添加到存档中 包含其他空目录的空目录也会被静默跳过 我可以使用 7Zip 创建相同路径的
  • 使用 Powershell 从多个 XML 文件中的元素获取数据,以便输出到另一个单个 XML 文件

    首先我要承认我是一个 Powershell 和编码 菜鸟 我摸索着写了一些剧本 但我并没有声称自己有任何接近能力的东西 我希望一些更有经验的人能让我走上正确的道路 我正在尝试从多个 XML 文件中提取特定的元素数据 这些数据将用于填充另一个
  • 了解 DICOM 图像属性以获得轴向/冠状/矢状切割 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我必须用 C 编写一个程序 能够解析 DICOM 并显示轴向 冠状和矢状切割 看起来工作量很大 但我必须这样做 我猜 重要的第一步是理解 DICOM 文件 我一直在读这个教程ht
  • Locale.getDefault() 返回Currency.getInstance 不支持/无效的区域设置

    我的应用程序使用以下代码来获取本地货币 Locale locale Locale getDefault java util Currency localCurrency java util Currency getInstance loca
  • 创建具有预先确定的平均值和标准差的数组

    我正在尝试使用 Numpy 创建一个具有预定平均值和标准差值的数组 该数组需要其中的随机数 到目前为止 我可以生成一个数组并计算平均值和标准差 但无法让数组受值控制 import numpy as np x np random randn
  • 如何将数组设置为mysql用户变量

    我没想到会发现这如此困难 但我试图在 MySQL 中设置一个用户变量来包含一个值数组 我不知道如何做到这一点 所以尝试做一些研究 但很惊讶没有找到答案 我努力了 SET billable types client1 client2 clie
  • 将数据从 csv 转换为动态列表 (Flutter)

    我创建了一个加载 CSV 文件并将其显示为列表视图的应用程序 我使用了以下示例 https gist github com Rahiche 9b4b2d3b5c24dddbbe662b58c5a2dcd2 问题是我的列表不生成行 I flu
  • 如何在另一个 git 存储库中提交 git 存储库

    我正在开发一个使用 git 的应用程序 因此我需要测试它与 git 的集成 在我的 git 存储库中 我需要另一个存储库 my git repo tests another repo 在没有 git 子模块的情况下如何提交它 我不想为一个文
  • 检查 Selenium 中是否存在 Element

    我想检查 Selenium 中是否存在某个元素 如果存在 则为其分配一个名称 现在我有一些看起来像这样的东西 IWebElement size9 driver FindElement By CssSelector a data value
  • 观察者模式与反应器模式

    我一直在研究两者 但找不到任何真正的区别 我错过了什么吗 在网络上 有些人说观察者应该只处理一个事件 而反应器应该处理很多事件 但我不认为这是一个真正的区别 因为反应器可以像许多观察者一样被看到 有什么区别吗 或者新名称 Reactor 只
  • OpenReadStream 允许的最大大小

    OpenReadStream 允许的最大大小是多少 现在 使用 10MB 但我认为必须有一定的上限 可以带GB吗 在 ASP NET Core 5 0 中 上传文件的框架文件大小限制为 2 GB 但是 从 ASP NET Core 6 0
  • C 中的局部结构

    如果一个结构体仅在一个函数中使用 我可以在该函数中声明它吗 我可以这样做吗 int func struct int a b s s a 5 return s a gcc 被它噎住了 但它发出了一个看起来非常奇怪的错误 我无法理解 而不是说
  • 涉及多个表的外键约束

    我在 Postgres 9 3 数据库中有以下场景 表 B 和 C 参考表 A 表 C 有一个引用表 B 的可选字段 我想确保对于表 C 中引用表 B 的每一行 c b a c a 也就是说 如果 C 引用了 B 则两行应指向表 A 中的同