I have an entity-relationship diagram like this
So in PostgreSQL I've created three tables like these:
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)
)
As we can see from the diagram, a musical event must have at least one artist who plays in. I'm not sure how to implement this constraint in PostgreSQL. If a row in the table Play_In is deleted, I can simply create a trigger which checks that the musical event involved by the row has at least one other artist, and, if there isn't, raise an exception. However I can't create a trigger like this which activates when I insert a new musical event, in fact I can't insert a row in Play_in before the musical event involved is created, since this will violate the foreign key constraint. So the only ways that came to my mind are
Are there other options? Which is the best way to handle this situation and how to implement it?
This is a very difficult relationship to implement. Because:
plays_in
to events
, so the Event_Id
needs to be valid to insert a row in Play_In
.plays_in
record in order to create the Event
.Circular logic. There are some ways to "get around" the problem -- for instance by turning off or deferring constraints. So, one method is to insert the artists and events in a single transaction using deferred constraints. This works for Postgres and is probably the preferred solution for Postgres. It is not, however, a general solution for all databases.
Another solution is to have a special artist. This special artist would have a direct foreign key relationship from events
to artists
and be NOT NULL
. The problem is that one artist is "special" so would be queried separately.
I think my preferred approach if you really want to "enforce" this is to add an artist_count
to the events
table. This count can be maintained using triggers.
Then use a view to show valid events:
create view v_events as
select e.*
from events e
where artist_count > 0;
The code that uses the view would only have events that have valid artists and you won't have a problem populating the data.