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

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(使用前将#替换为@)

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

  • 如何查找 PostgreSQL 数据库的上次更新时间?

    我正在使用一个批量更新的 postgreSQL 数据库 我需要知道数据库 或数据库中的表 上次更新或修改的时间 两者都可以 我看到 postgreSQL 论坛上有人建议使用日志记录并查询日志 这对我不起作用 因为我无法控制客户端代码库 你可
  • TOAD 将 &String 视为绑定变量

    我正在使用 Oracle Data Integrator 开发一些 ETL 有时会使用 TOAD 测试部分代码 今天我遇到了 TOAD 的问题 我有一行像 AND column value like DEV PROD 当我尝试运行包含上面过
  • Oracle 中的 SQL 调优 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有任何文章 链接可以让我找到 SQL 调优 Oracle 的示例 如果能用例子来解释那就太好了 我需
  • 如何有效地从 DB2 表中删除所有行

    我有一个大约有 50 万行的表 我想删除所有行 如果我做简单的delete from tbl 事务日志已满 我不关心这种情况下的事务 无论如何我都不想回滚 我可以删除许多事务中的行 但是有更好的方法吗 如何有效地从 DB2 中的表中删除所有
  • 使用 Spark DataFrame 获取组后所有组的 TopN

    我有一个 Spark SQL DataFrame user1 item1 rating1 user1 item2 rating2 user1 item3 rating3 user2 item1 rating4 如何按用户分组然后返回TopN
  • 使用 MS Access 获取行的第一个实例

    EDITED 我有这个查询 我想SELECT表中记录的第一个实例petTable SELECT id pet ID FIRST petName First Description FROM petTable GROUP BY pet ID
  • SQL参数化查询不显示结果

    我的 DataAcess 类中有以下函数 但它没有显示任何结果 我的代码如下 public List
  • 连接两个表的查询的 SQL Server“FOR XML”输出

    我是 SQL Server 中 FOR XML 功能的新手 我正在使用 SQL Server 2012 我有两个表 Word 和 Word Expansion 样本数据 表 字 WordOID Word 1 PIPE 2 WIRE 表 Wo
  • 将 SQL 数据中的一行映射到 Java 对象

    我有一个 Java 类 其实例字段 以及匹配的 setter 方法 与 SQL 数据库表的列名相匹配 我想优雅地从表中获取一行 到 ResultSet 中 并将其映射到此类的实例 例如 我有一个 Student 类 其中包含实例字段 FNA
  • SQLite HAVING 比较错误

    我有一个测试 SQLite 表 用于存储带有值的报告数据 CREATE TABLE IF NOT EXISTS test fact daily revenue date TEXT revenue NUMERIC product TEXT I
  • SQL Server 用分隔符分割字符串

    我有一个输入字符串 100 2 3 101 2 1 103 2 3 我想解析它并将其添加到具有 3 列的表中 因此它应该是 f x col1 col2 col3 100 2 3 类似的其他数据以逗号分隔作为记录和 作为列 Thanks ni
  • 使用两个日期之间的随机日期时间更新每一行

    我有一个专栏叫date created我希望每一行保存一个随机日期 日期距当前时间为 2 天 我正在运行以下查询 但它会更新具有相同随机日期的所有行 我希望每一行都是随机的并且不相同 update table set date create
  • 如何在 SQL Server 中使用 nvarchar 变量为 unicode 用户添加前缀“N”?

    如何在 SQL Server 中使用 nvarchar 变量为 unicode 用户添加前缀 N 例如 给定这个变量 declare Query1 nvarchar max 我可以这样分配它 set Query1 N 但是如果我想使用怎么办
  • Google Cloud SQL - Postgresql 存储不断增长

    我最近开始修补 Google Cloud SQL PostgreSQL 我创建了一个空数据库 在 4 5 天的时间里 其存储使用量已增长到超过 20GB 它一直在上升 但数据库中没有数据 它甚至没有被使用 有谁知道会发生什么以及如何阻止它
  • 如何在不运行 PostgreSQL 服务器的情况下初始化 PostgreSQL 数据库

    在初始化脚本中 我想初始化 PostgreSQL 目录 但在此阶段不需要 也不希望 正在运行的 PostgreSQL 服务器 如果我只是创建集群 作为用户postgres initdb D 但是 我还需要创建 PostgreSQL 角色 创
  • Mysql 中 UNION 子句的替代方案

    我有两张桌子 表 a 表 b table a ID 1 2 3 4 5 7 table b ID 2 3 4 5 6 我必须得到这样的输出而无需UNION命令 ID 1 2 3 4 5 6 7 注意 我有一个联合解决方案 select fr
  • 独立对列进行排序,使得所有空值都位于每列的最后

    这是一个名为的示例表animal name color fox brown fox red dog gold 现在 我想要的是这样的结果 fox dog brown gold red 名称应该是结果的列 不同颜色值作为行 我的第一个想法是
  • 如何在 PostgreSQL 中使用具有多个值的 SQL LIKE 条件?

    有没有更短的方法来查找多个匹配项 SELECT from table WHERE column LIKE AAA OR column LIKE BBB OR column LIKE CCC 这个问题适用于 PostgreSQL 9 1 但如
  • 了解 SSMS 2008 中关系的更新和删除规则

    当我们定义外键约束时 我对 SQL Server 2008 Management Studio 中的更新和删除规则的含义感到困惑 我也没有找到相关的帮助文档 例如F1帮助 这是屏幕快照 如果有人能描述它们的含义并推荐一些相关文档来阅读 我将
  • Laravel leftJoin 仅右表的最后一条记录

    我是 Laravel 的新手 我有两张桌子 1 产品 2 价格 products id product int p key name varchar prices id price int p key id product int

随机推荐

  • 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 与此
  • 将外键关系限制为相关子类型的行

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