2

Database Model (Simplified)

I am developing an application using PHP and Yii Framework. I've been thinking about the most suitable database structure for the given functionality and here's what I've come up with. Yet I'm not 100% positive that's how it should be done so I've decided to ask the community.

App Description:

Registered users may participate in an event. Every event can have an unlimited number of users, called "participants of the event").

Once the event is over, every participant can leave a feedback about every other participant of the same event.

Database structure:

Since every event can have an unlimited number of users and users can participate in an unlimited number of events, I've created a table "Participant", which resolves the many-to-many relation.

Other tables are self-explanatory.

And here's the most important thing:

Every participant of an event can have the maximum number of feedbacks which equals the number of participants of the same event excluding the given participant (Example, if there are 5 participants of the event, the given participant can receive 4 feedbacks from participants of the same event).

Let me emphasize, only participants of the same event can leave a feedback (and only one) about the given participant.

Below are the steps I took to ensure the integrity of the database:

  1. I've created the "id" column in the "Participant" table to give a unique ID to every user who participates in a certain event. This ID is composite (user_id and practice_id concatenated together). So, the participant id of the user 23 who participated in event 14 would be 14-23.

You may ask why I decided to create a separate column with this ID instead of simply defining the primary key like this:

PRIMARY KEY (user_id, event_id)

Read on.

When the event is over, every participant can leave a feedback about the others. Now, this participant ID can be references by the foreign keys "sender_id" and "recipient_id" in the feedback table.

Further on, the primary key of the feedback table will also be formed by combining "the sender_id" and the "recipient_id", so if the user 23 wants to leave a feedback about the user 45 (both participated in the event 71), the primary key for the feedback would be: 71-45-71-23.

This approach allows us to make sure on the database level that no participant leaves a feedback about the same participant twice and that a user can't participate in the same event twice.

Questions:

  • Does this approach has the right to exist?
  • What are the pros and other, better way to approach this functionality?
  • Can I generate the primary keys based on the values of the other columns automatically on record insertion?
Eugene Krall
  • 503
  • 5
  • 20

1 Answers1

3

This is a bad design. Just make a 2-column primary key, and 2-column foreign keys to it. This is a fundamental anti-pattern called "encoding information in keys" which (thereby) are called "smart", "intelligent" or "concatenated" keys. A good key is a "dumb" key.

Eg::

Despite it now being easy to implement a Smart Key, it is hard to recommend that you create one of your own that isn't a natural key, because they tend to eventually run into trouble, whatever their advantages, because it makes the databases harder to refactor, imposes an order which is difficult to change and may not be optimal for your queries, requires a string comparison if the Smart Key includes non-numeric characters, and is less effective than a composite key in helping range-based aggregations. It also violates the basic relational guideline that every column should store atomic values

Smart Keys also tend to outgrow their original coding constraints

Besides, there is no need to do this.

Many DBMSes allow "computed columns" whose values are automatically calculated from other columns. To make one a primary key or foreign key you would usually need it "persisted", ie have take up memory like a normal column vs just being calculated when needed like a view. MySQL does not have these, but 5.7.5 has some functionality where they are called "generated columns", which can be "stored". But don't do this for PKs or FKs!

The actual design issue is handling database/SQL subtypes/hierarchies/inheritance/polymorphism.

philipxy
  • 14,867
  • 6
  • 39
  • 83
  • The explanation is neat. Actually, as I'm writing this, I've already figured out for myself that it would've been better to create a two-column primary key since I've already come upon a problem with my implementation. I guess I will have to do some changes. – Eugene Krall Feb 12 '15 at 12:25