问题描述
因此在Postgresql中,我创建了三个这样的表:
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中实现此约束。如果删除了表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
。问题是一位艺术家是“特殊”艺术家,因此将被单独查询。
我认为,如果您真的想“强制”执行此操作,我的首选方法是在artist_count
表中添加events
。可以使用触发器来维护此计数。
然后使用视图显示有效事件:
create view v_events as
select e.*
from events e
where artist_count > 0;
使用视图的代码只会包含具有有效艺术家的事件,并且填充数据不会有问题。