Question

I have 4 tables here, their relationship is like the following: enter image description here

For 'band' table, I have 4 columns: id, band_name, first_name, last_name. (first_name and last_name refer to columns in 'independent artist' table).

For 'independent artist' I have 3 columns: id, first_name, last_name.

For 'act' table, I have 3 column: id, performer, music. Here for the perfumer, I want to refer to both band and independent artist table.

For 'music' table, I have 3 columns: id, song_name, release_year.

I also predict future changes here, for instance if a team member in a band wants to change his last name, it will affect both the 'band' and 'independent artist' table.

Intuitively I think my solution is not good, can anyone provide better design for the tables? Thanks.

Was it helpful?

Solution

Here's my suggestion:

Band table:

  • band_id PK
  • band_name

Artist table:

  • artist_id PK
  • first_name
  • last_name

Band_members table:

  • band_id FK
  • artist_id FK

Acts table:

  • act_id PK
  • band_id FK

Music table:

  • music_id PK
  • song_name
  • release_year

Act_Contents table:

  • act_id FK
  • music_id FK

There's no need for a separate Independent Artists table. Just treat them as a band with just one member. And you should always use an ID as the foreign key, so you don't have to worry about updating references if an attribute changes; you just change it in one place, and the references are unaffected.

OTHER TIPS

You probably want to have a one-to-many relation between band and artist where a band may reference one or more artists (by id or artist). That way the first name, and last name stay in the artist table and are not duplicated in the band table.

As for the other problem that you are having - you can't reference columns from more than one foreign table in a relationship. You'd have to model that by either creating two columns in the Act table, one that references band and one that references artist and add a constraint that only one may be non-null, or something else.

That said, you may want to take a look at MusicBrainz for inspiration. I've worked with that database in the past and the project is being developed by lots of smart people that have worked on the model for a while.

You sad it - you need a performer linked to act, not band or artist. I mean you need an abstraction about the object linked to the act object. The performer will be then linked first to the band object and second to the artist. You'll need to determine grammatically if a performer is a band or an independent artist depending on the present link to one of both objects. And of course you need a many-to-many relation between band and artist. Something like this:

band(id PK, name)
artist(id PK, first_name, last_name)
band_artists(band_id, artist_id)
performer(id PK, band_id, artist_id)
act(id PK, performer_id, music_id)
music(id, song_name, release_year)

I would not recommend you to use only one object for both band and artist because they have different meaning and own life. In the future you may want to add some physical characteristics to the artist for instance that are not relevant to a bad and so on.

It will be easy to know when a performer is a band or an artist. In the first case you'll have a non-NULL value for the band_id field. In the second you'll have a NULL value in the band_id and non-NULL value in the artist_id field.

If you need to retrieve an information about the performer related to a song for example you can do it in the following way:

SELECT 
    music.song_name, 
    performer.id as performer_id, 
    group.name as group_name,
    artist.first_name,
    artist.second_name
FROM music 
    LEFT JOIN act on music.id = act.music_id
    LEFT JOIN performer on act.performer_id = performer.id
    LEFT JOIN band on performer.band_id = band.id
    LEFT JOIN artist on performer.artist_id = artist.id

Now if your program logic you need to calculate the performer name:

if performer.band_name is not None:
    performer.name = performer.band_name
else:
    performer.name = performer.first_name + ' ' + performer.last_name

I believe the example code is self explanatory even itś not in your programming language and given there is some preprocessing of the query's result to obtain the performer object used in the example.

I would suggest something like the following.

There is an act that is either an individual artist or a band as indicated by the act_type (artist_id and band_id are both primary keys of their respective tables and a foreign key to act_id). A band is a collaboration of one or more individual artists, or may be a collaboration of more than one band, or a collaboration of one or more bands and one or more individual artists.

There is a recording that is either an individual song or an album/EP as indicated by the recording type (song_id and album_id are both primary keys or their respective tables and a foreign key to recording_id). An album/EP consists of more than one individual songs.

A song must be associated with an act. However, an album may not be associated with an act directly, such as a compilation album. There may be acts who do not release recordings by themselves but only as part of a band. A recording may or may not have a release date if they are not available by themselves but only as part of an album.

+---------------------+     +----------+                 +----------------+     +---------------------------+
| ACT_RELATIONSHIPS   |     | ACTS     |                 | RECORDINGS     |     | RECORDING_RELATIONSHIPS   |
+---------------------+     +----------+                 +----------------+     +---------------------------+
| act_relationship_id |-----| act_id   |-----------------| recording_id   |-----| recording_relationship_id |
| parent_act_id       |-----| act_type |                 | recording_type |-----| parent_recording_id       |
| child_act_id        |     +----------+                 | act_id         |     | child_recording_id        |
| start_date          |      |        |                  | release_date   |     +---------------------------+
| end_date            |      |        |                  +----------------+
+---------------------+      |        |                       |      |
                             |        |                       |      |
                  +-------------+  +-----------+    +-----------+  +------------+
                  | ARTISTS     |  | BANDS     |    | SONGS     |  | ALBUMS     |
                  +-------------+  +-----------+    +-----------+  +------------+
                  | artist_id   |  | band_id   |    | song_id   |  | album_id   |
                  | family_name |  | band_name |    | song_name |  | album_name |
                  | given_name  |  +-----------+    +-----------+  +------------+
                  +-------------+

I agree with Barmar's answer but I would add a extra column for independent_artist and that value would be a Yes or a No.

Artist Table: *artist_id *First_Name *Last_Name *Independent_Artist

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top