您可能想要一些类似的东西。我删除了多余的 a.id 列,使其更易于阅读。
CREATE TABLE b (
id bigserial not null,
flag boolean not null,
primary key (id),
unique (id, flag)
);
id 上的主键约束防止重复的 ID 号。 id, flag 上的重叠约束允许这 pair 列成为外键约束的目标。
CREATE TABLE a (
b_id bigint not null,
flag boolean not null default true
check (flag = true),
primary key (b_id, flag),
foreign key (b_id, flag) references b (id, flag)
on delete cascade
);
为了让a 中的行仅引用b 中flag 为真的行,a 中的每一行必须 flag 设置为真。 flag 的默认值和检查约束保证了这一点。
现在让我们尝试插入一些行。
insert into b (flag) values (true);
insert into b (flag) values (true);
insert into b (flag) values (false);
到目前为止,一切都很好。现在为 a 设置一些行。
insert into a (b_id, flag) values (1, true);
insert into a (b_id, flag) values (2, true);
但是这个应该失败了。
insert into a (b_id, flag) values (3, true);
--ERROR: insert or update on table "a" violates foreign key constraint "a_b_id_fkey"
--DETAIL: Key (b_id, flag)=(3, t) is not present in table "b".
而这个应该失败。
insert into a (b_id, flag) values (3, false);
--ERROR: new row for relation "a" violates check constraint "a_flag_check"
--DETAIL: Failing row contains (3, f).
还有一件事
您需要考虑在更新表 b 中的标志时想要发生什么。你不能级联更新;这将导致a 中的一行引用b 中具有false 的行。
update b set flag = false where id = 1 and flag = true;
-- ERROR: update or delete on table "b" violates foreign key constraint "a_b_id_fkey" on table "a"
-- DETAIL: Key (id, flag)=(1, t) is still referenced from table "a".
如何处理取决于应用程序。在某些应用程序中,当b 中的行更新为false 时,删除a 中的行可能是合适的。在其他应用程序中,仅撤销b 的更新权限可能是合适的。 (还有其他选项。)无论如何,您都需要编写一个触发器。