sql - PostgreSQL 多个表的循环外键
问题描述
我有 3 张桌子。
聊天室
create table chat_room
(
id uuid default uuid_generate_v4() not null
constraint chat_room_pk
primary key
constraint fk__chat_room__group_chat_room
references group_chat_room
on update cascade on delete cascade
constraint fk__chat_room__private_chat_room
references private_chat_room
on update cascade on delete cascade,
name varchar(255) not null,
description varchar(255),
profile_pic varchar(128),
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone
);
group_chat_room
create table group_chat_room
(
id uuid not null
constraint group_chat_room_pk
primary key
constraint fk__group_chat_room___chat_room
references chat_room
on update cascade on delete cascade,
pus_code char(7) not null
constraint fk__group_chat_room__puskesmas
references puskesmas
on update cascade on delete cascade
);
create unique index group_chat_room_pus_code_uindex
on group_chat_room (pus_code);
私人聊天室
create table private_chat_room
(
id uuid not null
constraint private_chat_room_pk
primary key
constraint fk__private_chat_room__chat_room
references chat_room
on update cascade on delete cascade
);
如您所见chat_room
,具有引用group_chat_room
and的外键约束private_chat_room
。并且两者group_chat_room
都有private_chat_room
FK 约束,指的是chat_room
.
当我想INSERT
连续进入时group_chat_room
,我会使用它
with chat_room as (
insert into chat_room (id, name) values ('Some ID', 'Some Name')
)
insert into group_chat_room(id, pus_code) values ('Some ID', 'Some Code');
但是,由于这些限制,这会产生错误
[23503] ERROR: insert or update on table "chat_room" violates foreign key constraint "fk__chat_room__private_chat_room" Detail: Key (id)=(cef8c655-d46a-4f63-bdc8-77113b1b74b4) is not present in table "private_chat_room".
我如何只插入group_chat_room
而不必将其插入private_chat_room
?
解决方案
这里的主要问题是创建多个必需的双向外键。最终,您可能可以解决它。但它使数据模型更加复杂,代码也更加复杂。这是完全没有必要的。只需一张桌子即可完成您所拥有的一切。如果 group_chat_room 和 private_chat_room 是独立需要的,则为每个创建一个视图。此外,作为简单视图,它们是完全可更新的。
您可以通过将“pus_code”列移动到 chat_room 并添加 2 个布尔值来指示这是私人房间还是团体房间或两者兼而有之。是的,听起来很奇怪,你可以得到一个 private_group_chat_room。(注意:您的设计中没有任何东西可以阻止它,您得到的错误是因为它是必需的)。如果您确实想要,那么创建一个检查约束,要求至少 1 个布尔列为假。
create table chat_room
(
id integer generated always as identity
constraint chat_room_pk
primary key,
name varchar(255) not null,
description varchar(255),
profile_pic varchar(128),
is_private boolean not null default false,
is_group boolean not null default false,
pus_code varchar(7)
constraint fk__group_chat_room__puskesmas
references puskesmas
on update cascade on delete cascade,
created_at timestamp with time zone default now() not null,
updated_at timestamp with time zone,
constraint not_group_of_pus_code_check
check ( (not is_group and pus_code is null)
or (is_group and pus_code is not null)
)
);
-- create unique partial index
create unique index group_chat_room_pus_code_uindex on chat_room(pus_code)
where is_group;
-- group_chat_room
create view group_chat_room
( id
, name
, description
, profile_pic
, is_private
, pus_code
, created_at
, updated_at
) as
select id
, name
, description
, profile_pic
, is_private
, pus_code
, created_at
, updated_at
from chat_room
where is_group;
-- private_chat_room
create view private_chat_room
( id
, name
, description
, profile_pic
, is_group
, pus_code
, created_at
, updated_at
) as
select id
, name
, description
, profile_pic
, is_group
, pus_code
, created_at
, updated_at
from chat_room
where is_private;
有关完整示例和一些测试,请参见小提琴。注意:小提琴的 generate_uuid_v4() 存在问题(不存在),因此对于演示,我更改为身份。在操作环境中会很好。
推荐阅读
- c# - 运算符不能应用于 string 和 int 类型的操作数
- c# - 如何使用 Nethereum 创建 Ethereum HD 钱包实现
- kubernetes - Kubernetes Ingress 不加载静态资产
- javascript - 关闭另一个选项卡/窗口
- influxdb - Inlfuxdb 保留策略被错误激活
- javascript - 如何从使用 rjxs 从 API 获取值的服务返回映射字符串?
- php - PHP用数组中的值替换字符串
- liferay - Liferay Service Builder 和 portlet 实例特定数据
- android - 删除资源 com.myapp.application:string/com_facebook_loginview_logged_in_using_facebook_f1gender 而不需要默认值
- angular - Angular 7 - 为选择/下拉框设置数据源