依赖于多个表的SQL约束

依赖于多个表的SQL约束,sql,postgresql,Sql,Postgresql,一旦我有了一个简单的数据库: CREATE TABLE workpiece ( id serial primary key -- More columns, not important here ); CREATE TABLE workequipment ( id serial primary key -- More columns, not important here ); CREATE TABLE workpiece_workequipment ( workpiec

一旦我有了一个简单的数据库:

CREATE TABLE workpiece
(
  id serial primary key
  -- More columns, not important here
);

CREATE TABLE workequipment
(
  id serial primary key
  -- More columns, not important here
);

CREATE TABLE workpiece_workequipment
(
  workpiece_id integer not null references workpiece(id),
  workequipment_id integer not null references workequipment(id),
  primary key(workpiece_id, workequipment_id)
);
但是现在需求改变了:我必须包括 工作设备(如工具、测量装置等) 并强调我们不能在每个工件上多次使用同一类型的工作设备

因此,我提出了以下建议:

CREATE TABLE workpiece
(
  id serial primary key
  -- More columns, not important here
);

CREATE TABLE workequipment
(
  id serial primary key,
  equipment_type integer, -- An enum in real world
  -- More columns, not important here
  unique(id, equipment_type)
);

CREATE TABLE workpiece_workequipment
(
  workpiece_id integer not null references workpiece(id),
  workequipment_id integer not null,
  workequipment_type integer not null,
  primary key(workpiece_id, workequipment_id),
  foreign key(workequipment_id, workequipment_type) references workequipment(id, equipment_type),
  unique(workpiece_id, workequipment_type)
);
使用这种冗余来强制约束可以吗? 如果是,我是否应该在工作台设备中删除唯一的(id、设备类型) 并将(id、设备类型)改为主键?
还是有更好的解决方案?

这很难看,但我也找不到更好的解决方案


您必须在
工作设备上保留主键和唯一约束,否则您可能会得到重复的
id
s。

您需要功能唯一索引:

CREATE TABLE workpiece
(
  id serial primary key
  -- More columns, not important here
);

CREATE TABLE workequipment
(
  id serial primary key,
  equipment_type integer
  -- More columns, not important here
);

CREATE TABLE workpiece_workequipment
(
  workpiece_id integer not null references workpiece(id),
  workequipment_id integer not null references workequipment(id),
  primary key(workpiece_id, workequipment_id)
);

-- Magic starts here :)

create function get_workequipment_type(int) returns int immutable language sql as $$
  select equipment_type from workequipment where id = $1
$$;

create unique index idx_check_wetype_unique
  on workpiece_workequipment(workpiece_id, get_workequipment_type(workequipment_id));
测试:


我不知道你可以根据函数的返回值创建索引,谢谢你。@candidus欢迎你。根据我的经验,当你在一张表上根据另一张表检查某些内容时,首先要考虑的是功能约束/索引。此解决方案在不重新编制索引的情况下容易受到设备类型更新的影响。我保证永远不会这样做,但我很好奇是否有办法阻止这样的更新。你有什么建议吗?@candidus很好。如果您询问如何将字段设置为只读-有很多这样的QA,例如:
insert into workpiece values(default);
insert into workequipment(equipment_type) values(1),(1),(2);
insert into workpiece_workequipment values(1,1),(1,3); -- Works
--insert into workpiece_workequipment values(1,1),(1,2); -- Fails