构建数据库关系以跟踪应用程序设置的不同变化
Structuring database relationships for tracking different variations of app settings
我目前正在设计的一个应用程序允许用户创建自定义的竞争性联赛(可以把它想象成梦幻体育),每个用户都可以加入不同的联赛,每个联赛由多轮比赛组成,用户(以下简称作为玩家)将参加比赛,并可以为每个联赛建立的不同 criteria/accomplishments 赚取积分。以下是一些需要注意的关键信息:
- 积分在 league/season
期间的所有回合中累积
- 自定义点 criteria/weight 设置可以在每一轮中更改。我认为在大多数情况下,这些逐轮积分设置在联赛(即赛季)期间会保持相对一致,但联赛当然可以选择将其调高很多。按照我目前的设置方式,联盟将建立一组默认的联盟级积分设置,这将是每一轮的默认设置,但他们始终可以决定更新积分权重、添加新的积分设置或 deactivate/activate 他们。由于这些子设置可能因回合而异,我是否应该有一个 table 用于默认联赛级点设置,然后另一个用于包含所有设置的回合级子设置每轮实际执行?
- 同上,每一轮可以由不同的玩家组成;不一定是所有联赛 members/players 或每一轮的同一组球员所以我目前有一个 table 用于联赛球员,一个用于回合球员,然后是 table跟踪基本上具有外键 linking 到一堆其他 table 的每个玩家所获得的积分,这对我来说似乎有点奇怪。
这种方法是否有意义,还是我想得太多或遗漏了什么?下面是我编造的实体关系图的 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。
问题
显然,您已经了解了数据完整性的价值。例如。您试图确保联赛中一轮的球员实际上是在该联赛中注册的球员;等等。优秀。您正在尝试实现 关系完整性,这是合乎逻辑的(并且不同于引用完整性,后者是 SQL 的物理特征)。
- 您已经发现唯一的方法是使用复合键。出色的。复合键是关系数据库中的普通票价。
然而,第二个问题是你没有钥匙,你有物理 Record IDs
...声明为 "keys"。因此,您试图约束的逻辑事物(数据是逻辑的)不受约束。而那种努力,那种尝试,导致了很多关系……没有达到预期的结果。
关系键
- 正如 E F Codd 博士在关系模型中所定义的:
- a [关系,逻辑] 键 由数据组成
- 引用是按逻辑关系键
- 在 1960 年代的 记录归档系统 中,"theoreticians" 大量销售并冒用 "relational" 名称:
- 引用是物理的
Record ID
。
- 这样的原始系统没有关系完整性;没有关系权力;并且没有关系速度。
您正在使用声明为 "keys" 的 Record IDs
(这会让您感到困惑,因为它不是 Key,并且它具有 none键的属性)。然后尝试通过复合键获得一些关系完整性(您凭直觉知道只有关系模型提供)...但是您正在使用声明 Non-Keys,所以它失败了,并在尝试中制作了一个复杂的模型。
- 更正是使用逻辑关系键,和避免物理
Record IDs
此外,您的 CPK
是克服 "theoreticians" 局限性的一次伟大尝试,但它没有具体说明由哪些列组成。如果您使用 IDEF1X(关系数据建模标准),这很容易纠正:构成键的列、主列或备用列是明确的。
下一个问题是,您的逻辑行(与物理记录不同)不是唯一的,而 RM 要求逻辑行是唯一的。
- 例如。在
User
中,username
不是唯一的
username
实际上是逻辑键(这将使行唯一)
- 您还需要
(first_name, last_name)
上的唯一性,这是第二个逻辑键
- 如果你理解了上面的内容,你就会明白:
user_id
是 100% 无用的(没有任何作用,它只是一个 additional 列和一个 additional 索引,这是要避免的)
username
是真实的、合乎逻辑的 PRIMARY KEY
,在任何引用的地方都会迁移为 FOREIGN KEY
。
- 因此,FK 引用是逻辑的,指向 thing 本身,而不是物理的,指向指向 thing[=216= 的记录的指针] 可能是。
同样,你可以去掉所有的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。
我目前正在设计的一个应用程序允许用户创建自定义的竞争性联赛(可以把它想象成梦幻体育),每个用户都可以加入不同的联赛,每个联赛由多轮比赛组成,用户(以下简称作为玩家)将参加比赛,并可以为每个联赛建立的不同 criteria/accomplishments 赚取积分。以下是一些需要注意的关键信息:
- 积分在 league/season 期间的所有回合中累积
- 自定义点 criteria/weight 设置可以在每一轮中更改。我认为在大多数情况下,这些逐轮积分设置在联赛(即赛季)期间会保持相对一致,但联赛当然可以选择将其调高很多。按照我目前的设置方式,联盟将建立一组默认的联盟级积分设置,这将是每一轮的默认设置,但他们始终可以决定更新积分权重、添加新的积分设置或 deactivate/activate 他们。由于这些子设置可能因回合而异,我是否应该有一个 table 用于默认联赛级点设置,然后另一个用于包含所有设置的回合级子设置每轮实际执行?
- 同上,每一轮可以由不同的玩家组成;不一定是所有联赛 members/players 或每一轮的同一组球员所以我目前有一个 table 用于联赛球员,一个用于回合球员,然后是 table跟踪基本上具有外键 linking 到一堆其他 table 的每个玩家所获得的积分,这对我来说似乎有点奇怪。
这种方法是否有意义,还是我想得太多或遗漏了什么?下面是我编造的实体关系图的 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。
问题
显然,您已经了解了数据完整性的价值。例如。您试图确保联赛中一轮的球员实际上是在该联赛中注册的球员;等等。优秀。您正在尝试实现 关系完整性,这是合乎逻辑的(并且不同于引用完整性,后者是 SQL 的物理特征)。
- 您已经发现唯一的方法是使用复合键。出色的。复合键是关系数据库中的普通票价。
然而,第二个问题是你没有钥匙,你有物理
Record IDs
...声明为 "keys"。因此,您试图约束的逻辑事物(数据是逻辑的)不受约束。而那种努力,那种尝试,导致了很多关系……没有达到预期的结果。关系键
- 正如 E F Codd 博士在关系模型中所定义的:
- a [关系,逻辑] 键 由数据组成
- 引用是按逻辑关系键
- 在 1960 年代的 记录归档系统 中,"theoreticians" 大量销售并冒用 "relational" 名称:
- 引用是物理的
Record ID
。 - 这样的原始系统没有关系完整性;没有关系权力;并且没有关系速度。
- 引用是物理的
- 正如 E F Codd 博士在关系模型中所定义的:
您正在使用声明为 "keys" 的
Record IDs
(这会让您感到困惑,因为它不是 Key,并且它具有 none键的属性)。然后尝试通过复合键获得一些关系完整性(您凭直觉知道只有关系模型提供)...但是您正在使用声明 Non-Keys,所以它失败了,并在尝试中制作了一个复杂的模型。- 更正是使用逻辑关系键,和避免物理
Record IDs
- 更正是使用逻辑关系键,和避免物理
此外,您的
CPK
是克服 "theoreticians" 局限性的一次伟大尝试,但它没有具体说明由哪些列组成。如果您使用 IDEF1X(关系数据建模标准),这很容易纠正:构成键的列、主列或备用列是明确的。下一个问题是,您的逻辑行(与物理记录不同)不是唯一的,而 RM 要求逻辑行是唯一的。
- 例如。在
User
中,username
不是唯一的
username
实际上是逻辑键(这将使行唯一)- 您还需要
(first_name, last_name)
上的唯一性,这是第二个逻辑键 - 如果你理解了上面的内容,你就会明白:
user_id
是 100% 无用的(没有任何作用,它只是一个 additional 列和一个 additional 索引,这是要避免的)username
是真实的、合乎逻辑的PRIMARY KEY
,在任何引用的地方都会迁移为FOREIGN KEY
。- 因此,FK 引用是逻辑的,指向 thing 本身,而不是物理的,指向指向 thing[=216= 的记录的指针] 可能是。
- 例如。在
同样,你可以去掉所有的
Record IDs
。
关系数据模型
你受过物理教育(假名"relational"),你试图'move up'进入逻辑。好主意,但这行不通。逻辑首先出现,准备就绪后,一个 'moves down' 进入物理。物理服务于逻辑,而不是相反。
试试这个。
注意 • 表示法
我所有的数据模型都在 IDEF1X 中呈现,这是自 1993 年以来的关系数据库建模标准
我的IDEF1X Introduction是初学者必读的
IDEF1X Anatomy给逝去的人一个温习
注意•内容
关系键
- 所有键都是逻辑关系键,它们是组合键
- 所有数据都受关系键约束(这是关系完整性)
- A
round_player
必须在league
中注册,round
在 中
- A
round_default_weight
必须是为round
在 中的 - 等等
- 如果您在 (a) 声明或 (b) 编码外键(复合外键)时遇到困难,请告诉我,我会提供。
league
设置的有效league_weights
之一独家亚型
- 每个
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 around
?
是的。
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。