构建数据库关系以跟踪应用程序设置的不同变化

Structuring database relationships for tracking different variations of app settings

我目前正在设计的一个应用程序允许用户创建自定义的竞争性联赛(可以把它想象成梦幻体育),每个用户都可以加入不同的联赛,每个联赛由多轮比赛组成,用户(以下简称作为玩家)将参加比赛,并可以为每个联赛建立的不同 criteria/accomplishments 赚取积分。以下是一些需要注意的关键信息:

这种方法是否有意义,还是我想得太多或遗漏了什么?下面是我编造的实体关系图的 link 图像,我觉得它有点不稳定,尤其是获得的积分 table,但这可能只是由于我缺乏设计关系数据库的经验。请注意,以“CPK”列出的字段是复合主键,由 table 中相应外键的串联组成。欢迎任何和所有反馈,谢谢!

ERD:

确认

[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?

是的。您隐含声明的是,一轮有一个设置,即:

  • 或者 league-level 设置
  • 自定义设置。

这是逻辑中典型的或门,在关系数据库中有一个正确的方法来实现它:独占子类型

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

这是正确的:它们是两个离散的事实,后者是前者的依赖。这意味着:

  • 玩家必须首先注册为league_player
  • 因此,玩家可以注册为 round_player
    • 在他注册为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

您的数据模型在那个时候超出了 rails。


问题

  1. 显然,您已经了解了数据完整性的价值。例如。您试图确保联赛中一轮的球员实际上是在该联赛中注册的球员;等等。优秀。您正在尝试实现 关系完整性,这是合乎逻辑的(并且不同于引用完整性,后者是 SQL 的物理特征)。

    • 您已经发现唯一的方法是使用复合键。出色的。复合键是关系数据库中的普通票价。
  2. 然而,第二个问题是你没有钥匙,你有物理 Record IDs ...声明为 "keys"。因此,您试图约束的逻辑事物(数据是逻辑的)不受约束。而那种努力,那种尝试,导致了很多关系……没有达到预期的结果。

  3. 关系键

    • 正如 E F Codd 博士在关系模型中所定义的:
      • a [关系,逻辑] 键 由数据组成
      • 引用是按逻辑关系键
    • 在 1960 年代的 记录归档系统 中,"theoreticians" 大量销售并冒用 "relational" 名称:
      • 引用是物理的 Record ID
      • 这样的原始系统没有关系完整性;没有关系权力;并且没有关系速度。
  4. 您正在使用声明为 "keys" 的 Record IDs(这会让您感到困惑,因为它不是 Key,并且它具有 none键的属性)。然后尝试通过复合键获得一些关系完整性(您凭直觉知道只有关系模型提供)...但是您正在使用声明 Non-Keys,所以它失败了,并在尝试中制作了一个复杂的模型。

    • 更正是使用逻辑关系键,避免物理Record IDs
  5. 此外,您的 CPK 是克服 "theoreticians" 局限性的一次伟大尝试,但它没有具体说明由哪些列组成。如果您使用 IDEF1X(关系数据建模标准),这很容易纠正:构成键的列、主列或备用列是明确的。

  6. 下一个问题是,您的逻辑行(与物理记录不同)不是唯一的,而 RM 要求逻辑行是唯一的。

    • 例如。在 User 中,username 不是唯一的
    • username 实际上是逻辑键(这将使行唯一)
    • 您还需要 (first_name, last_name) 上的唯一性,这是第二个逻辑键
    • 如果你理解了上面的内容,你就会明白:
      • user_id 是 100% 无用的(没有任何作用,它只是一个 additional 列和一个 additional 索引,这是要避免的)
      • username 是真实的、合乎逻辑的 PRIMARY KEY,在任何引用的地方都会迁移为 FOREIGN KEY
      • 因此,FK 引用是逻辑的,指向 thing 本身,而不是物理的,指向指向 thing[=216= 的记录的指针] 可能是。
  7. 同样,你可以去掉所有的Record IDs

关系数据模型

你受过物理教育(假名"relational"),你试图'move up'进入逻辑。好主意,但这行不通。逻辑首先出现,准备就绪后,一个 'moves down' 进入物理。物理服务于逻辑,而不是相反。

试试这个。

注意 • 表示法

  • 我所有的数据模型都在 IDEF1X 中呈现,这是自 1993 年以来的关系数据库建模标准

  • 我的IDEF1X Introduction是初学者必读的

  • IDEF1X Anatomy给逝去的人一个温习

注意•内容

  • 关系键

    • 所有键都是逻辑关系键,它们是组合键
    • 所有数据都受关系键约束(这是关系完整性
    • A round_player 必须在 league 中注册,round
    • A round_default_weight 必须是为 round
    • 中的 league 设置的有效 league_weights 之一
    • 等等
    • 如果您在 (a) 声明或 (b) 编码外键(复合外键)时遇到困难,请告诉我,我会提供。
  • 独家亚型

    • 每个 round 有一个 round_default_weight xor 一个 round_custom_weight
    • 有关子类型实现的完整详细信息,请参阅 Subtype
  • 我不明白 point_setting 的确切含义。我将其理解为 应用 到建模的分数的权重。

  • 我不明白你为什么把Point Earned作为一个单独的文件(即分开到多个parents的问题)。这似乎是每得分一个记录。假设只有玩家可以得分,您可以将积分累积到 round_player 行。

  • 您的设计允许每个 league 多个管理员,而不是一个。请确认。

尽情享受吧。请随时提出具体问题。可能有说明:确定后,我会发布一个进度数据模型。

评论

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

是的。

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.

好的。尝试这个。

  • 不需要为每个 round_player 每个 round 每个 point 维护一行。我们可以维护每个 point_type 的一行,其中包含每个 point_type 的总分。

  • 您需要指定 point_types(我以橄榄球得分类型为例)。

  • 是正常的table,不是Reference或"look-up"table,因为关系是Identifying。