-1

I have an entity-relationship diagram like this
enter image description here

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

  1. create a trigger that activates after a new row in Musical_Event is inserted, and calls a function that prompts the user to add a row in Play_In too (which refers to the same musical_event). But I don't know if this is possible.
  2. Create a function that inserts a row in both Musical_Event and Play_in (with musical_event column equal to the new musical event's id), and the user can insert a new row in Musical_Event only by using this function.
  3. Create a view as the join of Musical_Event and Play_in, with a trigger that activate every time a new row in inserted in the view and call a function that inserts the new values in Musical_Event and Play_In. The user can insert a new row in Musical_event only by inserting values in this view.

Are there other options? Which is the best way to handle this situation and how to implement it?

namerand
  • 33
  • 3

1 Answers1

1

This is a very difficult relationship to implement. Because:

  • You have a foreign key relationship from plays_in to events, so the Event_Id needs to be valid to insert a row in Play_In.
  • You are specifying, though, that you must have a 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.

Gordon Linoff
  • 1,122,135
  • 50
  • 484
  • 624
  • Thank you very much! I ended up setting foreign key constraint as deferred and creating a deferred trigger which assures that a new event has at least one artist. Now is possible to insert a new event only if in the same transaction a new row in `Play_In` for that event is inserted. – namerand Aug 29 '20 at 15:51
  • What happens when you have 1 artist for an event and that artist cancels? – Belayer Aug 29 '20 at 18:25
  • @Belayer I've crated a normal trigger to handle that situation. When a row in `Play_in` is deleted or when the field "event" of a row in `Play_In` is modified, the function called by the trigger check that in the old.event there is at least one other artists. If there isn't, an exception is raised and the deletion/modification of that row isn't allowed. – namerand Aug 29 '20 at 21:00
  • Good solution. Just always keep in mind you must look at all likely actions and even less likely ones. – Belayer Aug 29 '20 at 21:06