Postgres - 如何为来自差异表的两个不同列添加外键可为空约束

问题描述 投票:0回答:2

我有三个表1.帐户2.部门和3.经理 在经理表中,我需要添加帐户键和部门键作为外键,但其中一个将为空,另一个将具有值,这意味着如果插入客户经理,则部门键将为空,而帐户键将具有值。如何在postgres中添加约束

sql postgresql foreign-keys constraints
2个回答
1
投票

db<>fiddle 的演示

create table account(id serial primary key);
insert into account values (default);

create table dept(id serial primary key);
insert into dept values (default);

create table manager(
  id serial primary key,
  account_id int references account(id),
  dept_id int references dept(id) );

一个
null
,一个
not null

如果您始终希望其中一个外键为

null
,另一个为
not null
,则可以使用
XOR
。它不允许两者都具有值,也不允许它们同时存在的行
null
:

alter table manager add constraint dept_xor_account
  check( (account_id is null) != (dept_id is null) );

有一个 XOR

#
运算符,但仅适用于类型
bit
,所以它并不值得所有的转换:

alter table manager add constraint dept_xor_account
  check(((account_id is null)::int::bit # (dept_id is null)::int::bit)::int::bool);
insert into manager values(default,1,null);--works fine
insert into manager values(default,null,1);--works fine

insert into manager values(default,1,1);--can't have both links
ERROR:  new row for relation "manager" violates check constraint "dept_xor_account"
DETAIL:  Failing row contains (3, 1, 1).
insert into manager values(default,null,null);--can't have neither link
ERROR:  new row for relation "manager" violates check constraint "dept_xor_account"
DETAIL:  Failing row contains (4, null, null).

最多一个
null

如果你允许最多一个

null
(一个或两个都可以是
null
),你可以数一下:

alter table manager add constraint dept_or_account_or_neither
  check(((account_id is not null)::int+(dept_id is not null)::int)<2);

insert into manager values(default,1,null);--works fine
insert into manager values(default,null,1);--works fine
insert into manager values(default,null,null);--works fine, CAN have neither link

insert into manager values(default,1,1);--can't have both links
ERROR:  new row for relation "manager" violates check constraint "dept_or_account_or_neither"
DETAIL:  Failing row contains (8, 1, 1).

小提琴


0
投票

您的描述表明您不是在寻找“至多 1 个空值”,而是在寻找“恰好 1 个空值”。您可以通过将 num_nulls() 函数 合并到 check 约束中来确定这一点。所以(参见演示

create table manager(
  id serial primary key,
  account_id int references account(id),
  dept_id int references dept(id),
  constraint dept_xor_account check ( num_nulls(account_id,dept_id) = 1);

    

© www.soinside.com 2019 - 2024. All rights reserved.