PostgreSQL:实现最小基数数据库
PostgreSQL: implement minimum cardinality database
我有一个这样的实体关系图
所以在 PostgreSQL 中,我创建了三个 table,如下所示:
create table Artist(
id id primary key
)
create table Musical_Event(
id id primary key
)
create table Play_In(
artist id,
musical_event id,
primary key (artist, musical_event),
foreign key (artist) references Artist(id),
foreign key (musical_event) references Musical_Event(id)
)
从图中可以看出,音乐活动必须至少有一位艺术家参与。我不确定如何在 PostgreSQL 中实现此约束。如果 table Play_In 中的一行被删除,我可以简单地创建一个触发器来检查该行涉及的音乐事件是否至少有一位其他艺术家,如果没有,则提高一个例外。但是我无法创建这样的触发器,当我插入一个新的音乐事件时它会激活,实际上我无法在 Play_in 中插入一行,因为这会违反外键约束。所以我想到的唯一方法是
- 创建一个在 Musical_Event 中插入新行后激活的触发器,并调用提示用户在 Play_In 中添加一行的函数(指的是相同的 musical_event).但是我不知道这是否可能。
- 创建一个函数,在 Musical_Event 和 Play_in 中插入一行(musical_event 列等于新音乐事件的 ID),用户可以插入一个新行在 Musical_Event 中只能使用此功能。
- 创建一个视图作为 Musical_Event 和 Play_in 的连接,每次在视图中插入一个新行时都会激活一个触发器,并调用一个函数将新值插入 Musical_Event 和 Play_In。用户只能通过在此视图中插入值来在 Musical_event 中插入新行。
还有其他选择吗?处理这种情况的最佳方法是什么?如何实施?
这是一个很难实现的关系。因为:
- 您有从
plays_in
到 events
的外键关系,因此 Event_Id
需要有效才能在 Play_In
中插入一行。
- 不过,您指定必须有一个
plays_in
记录才能创建 Event
。
循环逻辑。有一些方法可以“解决”这个问题——例如通过关闭或推迟约束。因此,一种方法是使用 deferred constraints 在单个事务中插入艺术家和事件。这适用于 Postgres,可能是 Postgres 的首选解决方案。但是,它不是适用于所有数据库的通用解决方案。
另一种解决方案是请一位特别 艺术家。这位特殊的艺术家将具有从 events
到 artists
的直接外键关系,并且是 NOT NULL
。问题是一位艺术家是“特殊”的,因此将被单独查询。
如果你真的想“强制执行”,我认为我的首选方法是在 events
table 中添加一个 artist_count
。可以使用触发器维护此计数。
然后使用视图显示有效事件:
create view v_events as
select e.*
from events e
where artist_count > 0;
使用该视图的代码只会包含具有有效艺术家的事件,并且您不会在填充数据时遇到问题。
我有一个这样的实体关系图
所以在 PostgreSQL 中,我创建了三个 table,如下所示:
create table Artist(
id id primary key
)
create table Musical_Event(
id id primary key
)
create table Play_In(
artist id,
musical_event id,
primary key (artist, musical_event),
foreign key (artist) references Artist(id),
foreign key (musical_event) references Musical_Event(id)
)
从图中可以看出,音乐活动必须至少有一位艺术家参与。我不确定如何在 PostgreSQL 中实现此约束。如果 table Play_In 中的一行被删除,我可以简单地创建一个触发器来检查该行涉及的音乐事件是否至少有一位其他艺术家,如果没有,则提高一个例外。但是我无法创建这样的触发器,当我插入一个新的音乐事件时它会激活,实际上我无法在 Play_in 中插入一行,因为这会违反外键约束。所以我想到的唯一方法是
- 创建一个在 Musical_Event 中插入新行后激活的触发器,并调用提示用户在 Play_In 中添加一行的函数(指的是相同的 musical_event).但是我不知道这是否可能。
- 创建一个函数,在 Musical_Event 和 Play_in 中插入一行(musical_event 列等于新音乐事件的 ID),用户可以插入一个新行在 Musical_Event 中只能使用此功能。
- 创建一个视图作为 Musical_Event 和 Play_in 的连接,每次在视图中插入一个新行时都会激活一个触发器,并调用一个函数将新值插入 Musical_Event 和 Play_In。用户只能通过在此视图中插入值来在 Musical_event 中插入新行。
还有其他选择吗?处理这种情况的最佳方法是什么?如何实施?
这是一个很难实现的关系。因为:
- 您有从
plays_in
到events
的外键关系,因此Event_Id
需要有效才能在Play_In
中插入一行。 - 不过,您指定必须有一个
plays_in
记录才能创建Event
。
循环逻辑。有一些方法可以“解决”这个问题——例如通过关闭或推迟约束。因此,一种方法是使用 deferred constraints 在单个事务中插入艺术家和事件。这适用于 Postgres,可能是 Postgres 的首选解决方案。但是,它不是适用于所有数据库的通用解决方案。
另一种解决方案是请一位特别 艺术家。这位特殊的艺术家将具有从 events
到 artists
的直接外键关系,并且是 NOT NULL
。问题是一位艺术家是“特殊”的,因此将被单独查询。
如果你真的想“强制执行”,我认为我的首选方法是在 events
table 中添加一个 artist_count
。可以使用触发器维护此计数。
然后使用视图显示有效事件:
create view v_events as
select e.*
from events e
where artist_count > 0;
使用该视图的代码只会包含具有有效艺术家的事件,并且您不会在填充数据时遇到问题。