Structuring database relationships for tracking di

2020-02-16 03:49发布

An app I'm currently designing allows users to create custom competitive leagues (think of it kind of like fantasy sports) and each user can join different leagues and each league consists of multiple rounds where the users (hereafter referred to as Players) will compete and can earn points for different criteria/accomplishments established for each league. Here's some key info to note:

  • Points are accrued across all the rounds during a league/season
  • The custom point criteria/weight settings can change across each round. I’m thinking that for the most part these round-by-round point settings will stay relatively consistent during the span of a league (i.e. season) but a league could certainly choose switch it up a lot. With the way I currently have things setup, the league will establish a group of default league-level point settings that will be the default for each round but they can always decide to either update the point weights, add new point settings or deactivate/activate them. Because of these sub-settings that could vary from round-to-round, should I have one table for the default league-level point setting and then another for round-level sub-settings that will include all of the settings actually implemented for each round?
  • Similar to the above, each round can consist of different players; it’s not necessarily going to be all the league members/players or the same group of players in each round so I currently have one table for league player and one for round player and then a table that tracks the points earned for each player that basically has foreign keys linking to a bunch of other tables, which seems a little weird to me.

Does this approach make sense or am I overthinking or missing something? Below is a link to an image of an entity relationship diagram that I’ve concocted and it just feels a little wonky to me, especially with the Point Earned table, but that may just be due to my lack of experience with designing relational databases. Note that the fields listed with ‘CPK’ are composite primary keys that consist of the concatenation of the corresponding foreign keys in that table. Any and all feedback is welcome, thanks!

link to image of ERD

1条回答
对你真心纯属浪费
2楼-- · 2020-02-16 04:12

Confirmation

[Paraphrased] Because the point settings could vary from round-to-round, should I have:

  • one table for the default league-level point setting
  • and then another for round-level point setting

that will record the point setting actually implemented for each round?

Yes. What you are implicitly declaring is, a round has one setting, which is:

  • either the league-level setting
  • or a custom setting.

That is a typical OR Gate in Logic, and there is a correct method to implement that in a RElational database: an Exclusive Subtype.

I currently have one table for league player and one for round player

That is correct: they are two discrete Facts, the latter is Dependent on the former. That means:

  • a player has to first be registered as a league_player
  • consequently, a player can be registered as a round_player
    • and only in a league in which he is registered as a league_player.

and then table that tracks the points earned for each player that basically has foreign keys linking to a bunch of other tables

Your data model goes off the rails at that point.


Problem

  1. Evidently, you have learned the value of data integrity. Eg. you are attempting to ensure that a player in a round in a league is actually a player who is registered in that league; etc. Excellent. You are trying to achieve Relational Integrity, which is logical (and distinct from Referential Integrity, which is a physical feature of SQL).

    • You have figured out that the only way to do that is to use Composite Keys. Excellent. Composite Keys are ordinary fare in a Relational database.
  2. The second problem, however, is that you don't have keys, you have physical Record IDs ... declared as "keys". Therefore the logical thing (data is logical) that you are trying to constrain isn't constrained. And that effort, that attempt, results in scores of relationships ... that do not achieve the desired result.

  3. Relational Key

    • As defined by Dr E F Codd in the Relational Model:
      • a [Relational, logical] Key is made up from the data
      • references are by logical Relational Key
    • In 1960's Record Filing Systems, which are heavily marketed by the "theoreticians" and fraudulently named "relational":
      • references are by physical Record ID.
      • Such primitive systems have no Relational Integrity; no Relational Power; and no Relational Speed.
  4. You are using Record IDs declared as "keys" (that will confuse the hell out of you, because it is not a Key, and it has none of the properties of a Key). And then trying to get some Relational Integrity (which you intuitively know only the Relational Model provides) through Composite Keys ... but you are using the declared Non-Keys, so it fails, and makes a complex model in the attempt.

    • The correction is to use logical Relational Keys, and to avoid physical Record IDs
  5. Also, your CPK is a great attempt to overcome the limitations of the "theoreticians", but it does not specify precisely what columns make it up. That is easily corrected if you use IDEF1X (the standard for modelling Relational data): the columns that make up the Key, Primary or Alternate, are explicit.

  6. The next problem is, your logical rows (as distinct from physical records) are not unique, and the RM demands that logical rows are unique.

    • Eg. in User, username is not unique
      jasonr_user
    • username is actually the logical Key (which would make the rows unique)
    • you also need uniqueness on (first_name, last_name), which is a second logical Key
    • If you understand the above, you will understand that:
      • user_id is 100% useless (achieves nothing, it is merely an additional column and an additional index, which is to be avoided)
      • username is the real, logical, PRIMARY KEY, which is migrated as FOREIGN KEY wherever it is referenced.
      • The FK reference is therefore logical, to the thing itself, and not physical, to the pointer to a record in which the thing might be.
  7. Likewise, you can get rid of all the Record IDs.

Relational Data Model

You have been schooled in the physical (falsely named "relational"), and you have tried to 'move up' into the logical. Great idea, but that does not work. The logical comes first, and when ready, one 'moves down' into the physical. The physical serves the logical, not the reverse.

Try this.

jasonrTA1

Note • Notation

  • All my data models are rendered in IDEF1X, the Standard for modelling Relational databases since 1993

  • My IDEF1X Introduction is essential reading for beginners

  • The IDEF1X Anatomy is a refresher for those who have lapsed.

Note • Content

  • Relational Key

    • All Keys are logical Relational Keys, which are Composites
    • All data is constrained by Relational Keys (this is Relational Integrity)
    • A round_player must be registered in the league that the round is in
    • A round_default_weight must be one of the valid league_weights that have been set up for the league that the round is in
    • Et cetera
    • If you have difficulty either (a) declaring or (b) coding the Foreign Keys, which are Composites, let me know and I will provide it.
  • Exclusive Subtype

    • Each round has either one round_default_weight xor one round_custom_weight
    • Refer to Subtype for full details on Subtype implementation.
  • I do not understand what you mean precisely by point_setting. I understand it to be a weight that is applied to the score, which is modelled.

  • I do not understand why you have Point Earned as a separate file (ie. separate to the issue of multiple parents). That appears to be one record per point scored. Assuming that only players can score points, you can instead accumulate points into the round_player row.

  • Your design allows multiple admins per league, not one. Please confirm.

Enjoy. Please feel free to ask specific questions. There may be clarifications: when identified, I will issue a progressed data model.

Comments

If I track points in the round_player table would I only be able to track the total points earned during a round?

Yes.

For the points earned in each round I wanted to keep track of each point accrued by each player during each round so that you can look back and see the specific types of points and in what quantities they were earned for a player.

Ok. Try this.

jasonrTA2

  • There is no need to maintain one row per round_player per round per point. We can maintain a row per point_type containing total points per point_type instead.

  • You need to specify the point_types (I have given rugby point types as an example).

  • It is a normal table, not a Reference or "look-up" table, because the relation is Identifying.

查看更多
登录 后发表回答