【问题标题】:Exclusion constraint across two tables跨两个表的排除约束
【发布时间】:2019-10-30 13:27:58
【问题描述】:

我有两个表,用于存储两个不同应用程序实体的数据。两个实体都有一些公共字段,特别是父实体的外键和日期范围字段。我可以在每个表上创建一个排除约束,以确保同一父实体的日期范围不重叠,但我需要将此约束应用于两个组合的表。有没有办法在数据库级别实现这一点?

我认为我可以创建一个仅包含 parent_id 和 daterange 列以及排除约束的附加表,并在插入/更新/删除行时在上述两个表上添加触发器,但我对更简单的解决方案感兴趣如果有的话!

【问题讨论】:

  • 那么父实体中还有其他部分吗? (否则您只需将日期范围放在父表本身中)
  • 父子关系是一对多,所以不能把daterange放在parent上

标签: postgresql


【解决方案1】:

如果您希望设计保持当前状态,那么带触发器的解决方案可能是唯一的解决方案。

如果你愿意重新设计,你可以像这样对数据建模:

-- for the exclusion constraint
CREATE EXTENSION btree_gist;

CREATE TABLE parent (
   pid bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY
);

CREATE TABLE ranges (
   rid bigint NOT NULL GENERATED ALWAYS AS IDENTITY,
   pid bigint NOT NULL REFERENCES parent (pid),
   arange daterange NOT NULL,
   PRIMARY KEY (pid, rid),
   EXCLUDE USING gist (pid WITH =, arange WITH &&)
);

CREATE TABLE child1 (
   c1id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
   pid bigint NOT NULL REFERENCES parent (pid),
   rid bigint NOT NULL,
   FOREIGN KEY (rid, pid) REFERENCES ranges (rid, pid)
);

CREATE TABLE child2 (
   c2id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
   pid bigint NOT NULL REFERENCES parent (pid),
   rid bigint NOT NULL,
   FOREIGN KEY (rid, pid) REFERENCES ranges (rid, pid)
);

也就是说,将所有范围保留在一个表中,以便您可以定义排除约束。

【讨论】:

  • 这是一个有趣的解决方案!您是否希望这比使用触发器的解决方案更高效?
  • 不一定,因为外键是用 PostgreSQL 中的触发器实现的(尽管在 C 中)。性能问题只能通过测试来回答。但是经验表明,如果设计看起来很漂亮,并且查询自然且易于阅读,那么性能通常会很好。
  • 我喜欢这种哲学!谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
  • 2015-06-22
  • 1970-01-01
  • 2013-08-23
  • 1970-01-01
相关资源
最近更新 更多