PostgreSQL 中的外键过滤

Car*_*nks 6 postgresql constraints foreign-keys

我目前正在 PostgreSQL 中寻找一种方法,对于给定的表,我可以通过定义条件来限制可用的有效外键的数量。

所以场景是这样的

https://dbfiddle.uk/?rdbms=postgres_11&fiddle=4dbe279906dc8815​​98b7e72093534ce7

A、B、C 都代表不同的实体,每个具体的条目都列在 x_entry 表中。

表 A、B、C 都表示给定条目的版本,以及它们在什么时间跨度内有效。

我想确保表 A 始终具有 B 和 C 的外键,其中A.B.C == A.C时间跨度 A的条件。

如这里所见

在此处输入图片说明Ainit违反了 2000-3000 范围 的条件,因为binit在时间范围内2100-3000有一个外键cinot ,ainit 将其外键从 cinit 更改为cinat违反条件A.B.C == A.C

但是我如何设置这样的条件限制,以防止外键不违反这样的特定条件。? 甚至有可能吗?

Bjö*_*son 0

我目前正在 PostgreSQL 中寻找一种方法,对于给定的表,我可以通过定义条件来限制可用的有效外键的数量。

你不能那样做。

外键约束强制基于唯一性的引用完整性,例如“table_a.id == table_b.a_id”。您无法过滤重叠的日期范围或类似的内容。

我可以从根本上想到一种满足您要求的方法:触发器*

这并不太复杂,您在每个表上添加“BEFORE INSERT/DELETE/UPDATE”触发器,拒绝所有违反规则的插入/更新/删除。

如果你可以重组你的表,它会变得更容易,你只需要两个表:

entry
  id
  type ("a", "b" ,"c")
  name ("cinit", etc.)

PK entry(id, type)

entry_version
  id
  entry_id
  type ("a", "b" ,"c")
  valid_period (tsrange)

PK entry_version(id)
FK entry_version(entry_id, type) -> entry(id, type)
Run Code Online (Sandbox Code Playgroud)

现在您只需要在entry_version 上执行插入/更新/删除触发器来强制执行规则。

您可能想要研究的事情:

例如,您可以确保不能将日期范围重叠的两行放在同一个表中。

表分区您可以为每个有效期或其他时间设置不同的分区。(不过对你来说可能是一个死胡同)。

找出某种方法将日期范围转换为表中的行并使用外键引用它们。

*是的,还有规则:但那是专家级别