将外键关系限制为相关子类型的行

2023-12-04

概述:我试图表示数据库中的几种类型的实体,这些实体具有许多共同的基本字段,然后每个实体都有一些不与其他类型的实体共享的附加字段。工作流程经常涉及将实体列出在一起,因此我决定使用一个包含其公共字段的表,然后每个实体将拥有自己的包含附加字段的表。

实现:有一个公共字段“状态”,所有实体都有;但是,某些实体仅支持所有可能状态的子集。我还希望每种类型的实体强制使用其状态子集。最后,我还想在将实体列出在一起时包含此字段,因此将其从公共字段集中排除似乎是不正确的,因为这需要特定类型表的并集,并且 SQL 中缺少“实现接口”意味着该字段的纳入将是按照惯例。

为什么我在这里:下面是一个实用的解决方案,但我很感兴趣是否有更好或更常见的方法来解决问题。特别是,这个解决方案要求我做一个冗余的事实unique约束和冗余的状态字段感觉不优雅。

create schema test;

create table test.statuses(
    id      integer     primary key
);
create table test.entities(
    id      integer     primary key,
    status  integer,
    unique(id, status),
    foreign key (status) references test.statuses(id)
);

create table test.statuses_subset1(
    id      integer     primary key,
    foreign key (id) references test.statuses(id)
);
create table test.entites_subtype(
    id integer primary key,
    status integer,
    foreign key (id) references test.entities(id),
    foreign key (status) references test.statuses_subset1(id),
    foreign key (id, status) references test.entities(id, status) initially deferred
);

一些数据:

insert into test.statuses(id) values
    (1),
    (2),
    (3);
insert into test.entities(id, status) values
    (11, 1),
    (13, 3);
insert into test.statuses_subset1(id) values
    (1), (2);
insert into test.entites_subtype(id, status) values
    (11, 1);

-- Test updating subtype first
update test.entites_subtype
    set status = 2
    where id = 11;
update test.entities
    set status = 2
    where id = 11;

-- Test updating base type first
update test.entities
    set status = 1
    where id = 11;
update test.entites_subtype
    set status = 1
    where id = 11;

/* -- This will fail
insert into test.entites_subtype(id, status) values
    (12, 3);
*/

简化构建MATCH SIMPLEfk 约束的行为

如果多列外部约束中至少有一列具有默认值MATCH SIMPLE行为是NULL,不强制执行约束。您可以在此基础上进一步简化您的设计。

CREATE SCHEMA test;

CREATE TABLE test.status(
   status_id  integer PRIMARY KEY
  ,sub        bool NOT NULL DEFAULT FALSE  -- TRUE .. *can* be sub-status
  ,UNIQUE (sub, status_id)
);

CREATE TABLE test.entity(
   entity_id  integer PRIMARY KEY
  ,status_id  integer REFERENCES test.status  -- can reference all statuses
  ,sub        bool      -- see examples below
  ,additional_col1 text -- should be NULL for main entities
  ,additional_col2 text -- should be NULL for main entities
  ,FOREIGN KEY (sub, status_id) REFERENCES test.status(sub, status_id)
     MATCH SIMPLE ON UPDATE CASCADE  -- optionally enforce sub-status
);

It is 非常便宜存储一些额外的 NULL 列(对于主要实体):

  • 使用 postgresql DB 存储 NULL 值需要多少磁盘空间?

BTW, 根据文档:

If the refcolumn列表被省略,主键reftable用来。

演示数据:

INSERT INTO test.status VALUES
  (1, TRUE)
, (2, TRUE)
, (3, FALSE);     -- not valid for sub-entities

INSERT INTO test.entity(entity_id, status_id, sub) VALUES
  (11, 1, TRUE)   -- sub-entity (can be main, UPDATES to status.sub cascaded)
, (13, 3, FALSE)  -- entity  (cannot be sub,  UPDATES to status.sub cascaded)
, (14, 2, NULL)   -- entity  (can    be sub,  UPDATES to status.sub NOT cascaded)
, (15, 3, NULL)   -- entity  (cannot be sub,  UPDATES to status.sub NOT cascaded)

SQL小提琴(包括你的测试)。

单 FK 的替代方案

另一种选择是输入以下的所有组合(status_id, sub)进入status表(每张只能有 2 个status_id) 并且只有一个 fk 约束:

CREATE TABLE test.status(
   status_id  integer
  ,sub        bool DEFAULT FALSE
  ,PRIMARY KEY (status_id, sub)
);

CREATE TABLE test.entity(
   entity_id  integer PRIMARY KEY
  ,status_id  integer NOT NULL  -- cannot be NULL in this case
  ,sub        bool NOT NULL     -- cannot be NULL in this case
  ,additional_col1 text
  ,additional_col2 text
  ,FOREIGN KEY (status_id, sub) REFERENCES test.status
     MATCH SIMPLE ON UPDATE CASCADE  -- optionally enforce sub-status
);

INSERT INTO test.status VALUES
  (1, TRUE)       -- can be sub ...
  (1, FALSE)      -- ... and main
, (2, TRUE)
, (2, FALSE)
, (3, FALSE);     -- only main

Etc.

相关回答:

  • 完整匹配与简单匹配
  • 仅当第三列为 NOT NULL 时才使用两列外键约束
  • 当验证在另一个表上有条件时,数据库中的唯一性验证

保留所有表

如果您出于某种原因需要所有四个表,而不是在问题中,请考虑 dba.SE 上一个非常相似的问题的详细解决方案:

  • 强制执行“两张桌子之外”的约束

遗产

...可能是您所描述的另一种选择。如果你能和一些主要限制。相关回答:

  • 在PostgreSQL中创建两种类型的表
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将外键关系限制为相关子类型的行 的相关文章

随机推荐

  • Microsoft.Identity.Web 和 ASP.NET Core SignalR JWT 身份验证

    我正在使用 ASP NET Core 制作一个 Web 应用程序 该应用程序还使用 SignalR Core 来提供实时功能 我使用 Azure AD B2C 进行用户管理 我已经成功使用了Microsoft Identity Web ht
  • Spring中初始化多个数据库

    我正在使用 AbstractRoutingDatasource 在运行时在数据库之间进行路由 在 informix 数据库的实际情况下 一切工作正常 为了进行测试 我创建了一个 spring 配置文件以在内存 H2 数据库中使用 使用测试配
  • 如何在运行一次后“禁用”javascript函数

    所以我有两个 html 按钮 每个按钮运行不同的功能 两个功能都在下面 基本上 您单击两个按钮之一即可将 Google 地图操作侦听器添加到地图 我已经成功地让它发挥作用了 唯一的问题是我只希望动作监听器一键可用 单击一次之后 我希望用户必
  • if/else 构造内部和外部函数

    当我查看 R 函数时 我经常发现以下结构 f lt function exp T if exp a lt 1 else a lt 2 f f F 这将运行而不会出现错误 但是执行内部函数代码会引发错误 因为 R 可能假设该语句在第一次赋值后
  • iPhone - 保存 UIImageView 状态

    我创建了 UIImageView 的子类 并且正在子类本身内部处理其对象的触摸 现在 当用户即将退出应用程序时 我想保存图像的状态 由于图像上可能发生了多次转换 我将所有转换保存在一个数组中 我希望能够将这些对象保存在 applicatio
  • 导致 TFS InvokeProcess 构建活动在其他凭据下运行

    我们使用 InvokeProcess 操作自定义了构建过程 该操作运行部署 sln 的 powershell 脚本 问题是该脚本必须在给定用户 而不是 tfsbuild 用户 下运行 我们怎样才能做到这一点 替代方案 1 创建 Invoke
  • [].append(x) 行为

    这按照我的预期执行 gt gt gt x gt gt gt x append 3 gt gt gt x 3 为什么以下返回 None gt gt gt x append 3 gt gt gt x gt gt gt because list
  • openCV 中的结果比较Hist

    我正在尝试比较我存储为数组的两个直方图 我是 C 接口 cv Mat 和 OpenCV 中计算直方图的新手 My code int testArr1 4 12 10 11 11 int testArr2 4 12 0 11 0 cv Mat
  • 在 C# 中使用 POST/httpwebrequest 上传 zip 文件

    我正在尝试代码http www paraesthesia com archive 2009 12 16 posting multipartform data using net webrequest aspx通过 httpwebreques
  • 如何在超级账本结构中获取资产修改历史记录

    我在用IBM Bluemix 区块链服务为我的资产共享演示尝试一些智能合约逻辑 无论如何 是否可以查询超级账本结构网络中的资产修改历史记录 我检查了 Fabric 0 6 和 1 0 版本的文档 但我只能找到stub pushState k
  • 是否可以从 bdist 中排除数据文件源和中间文件?

    我正在使用 setuptools 构建许多数据文件 编译的翻译 图标调整大小并转换为不同的格式等 我想将这些数据文件的来源包含在sdist和构建结果 但不是它们的源和中间文件bdist wheel 当我使用package data源文件 中
  • 在值/键上加入 AngularFire 路径不起作用(将用户配置文件合并到记录中)

    我正在使用 Firebase 1 0 和 Angular 1 4 开发一个应用程序 我遇到的问题是确保视图中的数据与 Firebase 同步 同时从 Firebase 中的两个表获取非规范化数据 图书表如下所示 books JyDpkQrU
  • 检索由shiny::reactive()推断的反应性依赖关系

    考虑一下这个推介会Joe Cheng 解释了他和他的同事如何在闪亮中实现响应式框架 其灵感来自于Meteor 实际问题 有人可以向我解释一下我将如何找到一个反应式对象的依赖关系 即列出它们的名称和环境 实际访问它们等 这些是由shiny r
  • 在 while 循环内部设置的 Shell 变量在其外部不可见

    我试图找到其中字符最多的路径名 可能有更好的方法来做到这一点 但我想知道为什么会出现这个问题 LONGEST CNT 0 find samples while read line do line length echo line wc m
  • 禁用 Asp.Net WebAPI 中的默认验证

    我想完全禁用 WebAPI 控制器的模型验证 我尝试了几种方法来为 MVC 做到这一点 但似乎 WebAPI 没有得到这些方法 就我而言 自定义格式化程序创建并填充对象 默认验证发生 对象传递给控制器 我的代码开始工作 我正在尝试完全删除第
  • 有没有办法只接受 JTextField 中的数字值?

    有没有办法只接受 a 中的数字值JTextField 有什么特殊的方法吗 由于这个问题经常出现 所以我在这个答案上投入了比平时更多的努力 我的投票投给了JFormattedTextField IMO 每个 Swing 开发人员都应该在他 她
  • R:具有重复数据框的扩展函数

    我有一个需要旋转的数据框 但该数据框有重复的标识符 所以spread函数给出错误Error Duplicate identifiers for rows 5 6 Dimension c A A B B A A Date c Mon Tue
  • 无法在我的 Mac Mountain Lion 上运行 Composer - openssl 扩展

    我安装了几个需要 Composer 的 CMS 两天以来我遇到了错误 无法继续 RuntimeException You must enable the openssl extension to download files via htt
  • Powershell 中的管道

    我正在阅读有关 PowerShell 中管道如何工作的信息 about 管道 并了解管道一次传送一个对象 So this Get Service Format Table Property Name DependentServices 与此
  • 将外键关系限制为相关子类型的行

    概述 我试图表示数据库中的几种类型的实体 这些实体具有许多共同的基本字段 然后每个实体都有一些不与其他类型的实体共享的附加字段 工作流程经常涉及将实体列出在一起 因此我决定使用一个包含其公共字段的表 然后每个实体将拥有自己的包含附加字段的表