如何在PostgreSQL中生成对引用表具有约束的外键
假设我有下列表格如何在PostgreSQL中生成对引用表具有约束的外键,sql,postgresql,constraints,Sql,Postgresql,Constraints,假设我有下列表格 CREATE TABLE plugins ( id int primary key, type text); insert into plugins values (1,'matrix'); insert into plugins values (2,'matrix'); insert into plugins values (3,'function'); insert into plugins values (4,'function'); CREATE TABLE mat
CREATE TABLE plugins (
id int primary key,
type text);
insert into plugins values (1,'matrix');
insert into plugins values (2,'matrix');
insert into plugins values (3,'function');
insert into plugins values (4,'function');
CREATE TABLE matrix_params (
id int primary key,
pluginid int references plugins (id)
);
这一切都按预期进行,但我想添加一个额外的约束,即矩阵参数只能引用具有“matrix”类型的pluginid。所以
insert into matrix_params values (1,1);
应该成功但是
insert into matrix_params values (2,3);
应该失败
矩阵参数的简单约束不起作用,因为它无法知道插件表中对应的类型。对此可以使用检查约束。不能将查询置于检查约束中,但可以调用函数;因此,我们构建了一个简单的函数,告诉我们
pluginid
是否是矩阵:
create or replace function is_matrix(int) returns boolean as $$
select exists (
select 1
from plugins
where id = $1
and type = 'matrix'
);
$$ language sql;
并将其包装在检查约束中:
alter table matrix_params add constraint chk_is_matrix check (is_matrix(pluginid));
然后:
FK负责引用完整性和级联。在引用表中使用复合键,并在引用表中使用
检查约束,例如
CREATE TABLE plugins (
id int primary key,
type text,
UNIQUE (type, id)
);
CREATE TABLE matrix_params (
id int primary key,
plugintype text DEFAULT 'matrix' NOT NULL
CHECK (plugintype = 'matrix'),
pluginid int NOT NULL,
FOREIGN KEY (plugintype, pluginid)
references plugins (type, id)
);
处理此问题的一种方法是使用可序列化事务
如果在矩阵参数行引用插件行后更新了类型,则不会处于所需状态;否则这会起作用。@kgrittn:您可以在插件
上添加一个更新触发器(如果您的PostgreSQL版本支持,当old.type='matrix'和new.type!=old.type
条件时,可能带有),如果更新违反了is_matrix
条件,则该触发器可能引发异常。这可能有点难看。这会将一个表的主键更改为问题中未指定的内容,并在另一个表的每一行中添加一个不必要的列。@kgrittn:我没有更改任何主键:我已向引用的表添加了一个额外的超键。引用表中添加的列允许使用行级检查约束(使用外键),因此在上下文中是必要的。但如果你觉得麻烦的话,它可以通过视图“隐藏”。我认为这是一个有效的解决方案。当您通过plugintype来考虑它时,pluginid实际上并不是一个键,因为在plugins表中不允许使用(1,'foo')、(1,'bar)。在我的例子中,我试图使用一个常量作为键的一部分,postgres不喜欢它。我更喜欢选择的答案,因为它不需要修改数据类型就可以完成任务。对不起,你说得对。我想我应该在早上发布之前等待咖啡因的加入。好吧,如果没有一些非规范化(冗余地将数据存储在矩阵参数中)或者声明一个真正稳定的函数是不可变的,它带有一定的风险,那么这不可能是一个外键。(当你对数据库撒谎时,它迟早会报复你。)因此,唯一真正准确的答案是它无法做到。但这不是很有帮助。这是一种非常常见的用例类型,可序列化事务正是要解决的问题。也许我的链接应该在这里:
CREATE TABLE plugins (
id int primary key,
type text,
UNIQUE (type, id)
);
CREATE TABLE matrix_params (
id int primary key,
plugintype text DEFAULT 'matrix' NOT NULL
CHECK (plugintype = 'matrix'),
pluginid int NOT NULL,
FOREIGN KEY (plugintype, pluginid)
references plugins (type, id)
);